diff --git a/gin/b/b.go b/gin/b/b.go deleted file mode 100644 index b341c43..0000000 --- a/gin/b/b.go +++ /dev/null @@ -1,62 +0,0 @@ -package b - -import ( - "git.ningdatech.com/ningda/gin_valid/gin/binding" - "git.ningdatech.com/ningda/gin_valid/go-playground/validator/v10" - "mime" - "net/http" -) - -type ValidError struct { - ErrString string -} - -func (e *ValidError) Error() string { - return e.ErrString -} - -func ShouldBind(req *http.Request, obj interface{}) error { - content, err := contentType(req) - if err != nil { - return err - } - b := binding.Default(req.Method, content) - err = ShouldBindWith(req, obj, b) - errs, ok := err.(validator.ValidationErrors) - if !ok { - // 非validator.ValidationErrors类型错误直接返回 - return err - } - return errs.Translate(binding.ValidTrans) -} - -func ShouldBindWith(req *http.Request, obj interface{}, b binding.Binding) error { - return b.Bind(req, obj) -} -func ShouldBindJSON(req *http.Request, obj interface{}) error { - return ShouldBindWith(req, obj, binding.JSON) -} -func ShouldBindHeader(req *http.Request, obj interface{}) error { - return ShouldBindWith(req, obj, binding.Header) -} -func ShouldBindQuery(req *http.Request, obj interface{}) error { - return ShouldBindWith(req, obj, binding.Query) -} - -func contentType(r *http.Request) (string, error) { - ct := r.Header.Get("Content-Type") - if ct == "" { - ct = "application/octet-stream" - } - ct, _, err := mime.ParseMediaType(ct) - return ct, err -} - -func filterFlags(content string) string { - for i, char := range content { - if char == ' ' || char == ';' { - return content[:i] - } - } - return content -} diff --git a/gin/binding/binding.go b/gin/binding/binding.go deleted file mode 100644 index a87feb3..0000000 --- a/gin/binding/binding.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -// +build !nomsgpack - -package binding - -import "net/http" - -// Content-Type MIME of the most common data formats. -const ( - MIMEJSON = "application/json" - MIMEHTML = "text/html" - MIMEXML = "application/xml" - MIMEXML2 = "text/xml" - MIMEPlain = "text/plain" - MIMEPOSTForm = "application/x-www-form-urlencoded" - MIMEMultipartPOSTForm = "multipart/form-data" - MIMEPROTOBUF = "application/x-protobuf" - MIMEMSGPACK = "application/x-msgpack" - MIMEMSGPACK2 = "application/msgpack" - MIMEYAML = "application/x-yaml" -) - -// Binding describes the interface which needs to be implemented for binding the -// data present in the request such as JSON request body, query parameters or -// the form POST. -type Binding interface { - Name() string - Bind(*http.Request, interface{}) error -} - -// BindingBody adds BindBody method to Binding. BindBody is similar with Bind, -// but it reads the body from supplied bytes instead of req.Body. -type BindingBody interface { - Binding - BindBody([]byte, interface{}) error -} - -// BindingUri adds BindUri method to Binding. BindUri is similar with Bind, -// but it read the Params. -type BindingUri interface { - Name() string - BindUri(map[string][]string, interface{}) error -} - -// StructValidator is the minimal interface which needs to be implemented in -// order for it to be used as the validator engine for ensuring the correctness -// of the request. Gin provides a default implementation for this using -// https://git.ningdatech.com/ningda/gin_valid/go-playground/validator/tree/v8.18.2. -type StructValidator interface { - // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. - // If the received type is not a struct, any validation should be skipped and nil must be returned. - // If the received type is a struct or pointer to a struct, the validation should be performed. - // If the struct is not valid or the validation itself fails, a descriptive error should be returned. - // Otherwise nil must be returned. - ValidateStruct(interface{}) error - - // Engine returns the underlying validator engine which powers the - // StructValidator implementation. - Engine() interface{} -} - -// Validator is the default validator which implements the StructValidator -// interface. It uses https://git.ningdatech.com/ningda/gin_valid/go-playground/validator/tree/v8.18.2 -// under the hood. -var Validator StructValidator = &defaultValidator{} - -// These implement the Binding interface and can be used to bind the data -// present in the request to struct instances. -var ( - JSON = jsonBinding{} - XML = xmlBinding{} - Form = formBinding{} - Query = queryBinding{} - FormPost = formPostBinding{} - FormMultipart = formMultipartBinding{} - ProtoBuf = protobufBinding{} - MsgPack = msgpackBinding{} - YAML = yamlBinding{} - Uri = uriBinding{} - Header = headerBinding{} -) - -// Default returns the appropriate Binding instance based on the HTTP method -// and the content type. -func Default(method, contentType string) Binding { - if method == http.MethodGet { - return Form - } - - switch contentType { - case MIMEJSON: - return JSON - case MIMEXML, MIMEXML2: - return XML - case MIMEPROTOBUF: - return ProtoBuf - case MIMEMSGPACK, MIMEMSGPACK2: - return MsgPack - case MIMEYAML: - return YAML - case MIMEMultipartPOSTForm: - return FormMultipart - default: // case MIMEPOSTForm: - return Form - } -} - -func validate(obj interface{}) error { - if Validator == nil { - return nil - } - return Validator.ValidateStruct(obj) -} diff --git a/gin/binding/binding_nomsgpack.go b/gin/binding/binding_nomsgpack.go deleted file mode 100644 index 7e1b58d..0000000 --- a/gin/binding/binding_nomsgpack.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2020 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -// +build nomsgpack - -package binding - -import "net/http" - -// Content-Type MIME of the most common data formats. -const ( - MIMEJSON = "application/json" - MIMEHTML = "text/html" - MIMEXML = "application/xml" - MIMEXML2 = "text/xml" - MIMEPlain = "text/plain" - MIMEPOSTForm = "application/x-www-form-urlencoded" - MIMEMultipartPOSTForm = "multipart/form-data" - MIMEPROTOBUF = "application/x-protobuf" - MIMEYAML = "application/x-yaml" -) - -// Binding describes the interface which needs to be implemented for binding the -// data present in the request such as JSON request body, query parameters or -// the form POST. -type Binding interface { - Name() string - Bind(*http.Request, interface{}) error -} - -// BindingBody adds BindBody method to Binding. BindBody is similar with Bind, -// but it reads the body from supplied bytes instead of req.Body. -type BindingBody interface { - Binding - BindBody([]byte, interface{}) error -} - -// BindingUri adds BindUri method to Binding. BindUri is similar with Bind, -// but it read the Params. -type BindingUri interface { - Name() string - BindUri(map[string][]string, interface{}) error -} - -// StructValidator is the minimal interface which needs to be implemented in -// order for it to be used as the validator engine for ensuring the correctness -// of the request. Gin provides a default implementation for this using -// https://git.ningdatech.com/ningda/gin_valid/go-playground/validator/tree/v8.18.2. -type StructValidator interface { - // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. - // If the received type is not a struct, any validation should be skipped and nil must be returned. - // If the received type is a struct or pointer to a struct, the validation should be performed. - // If the struct is not valid or the validation itself fails, a descriptive error should be returned. - // Otherwise nil must be returned. - ValidateStruct(interface{}) error - - // Engine returns the underlying validator engine which powers the - // StructValidator implementation. - Engine() interface{} -} - -// Validator is the default validator which implements the StructValidator -// interface. It uses https://git.ningdatech.com/ningda/gin_valid/go-playground/validator/tree/v8.18.2 -// under the hood. -var Validator StructValidator = &defaultValidator{} - -// These implement the Binding interface and can be used to bind the data -// present in the request to struct instances. -var ( - JSON = jsonBinding{} - XML = xmlBinding{} - Form = formBinding{} - Query = queryBinding{} - FormPost = formPostBinding{} - FormMultipart = formMultipartBinding{} - ProtoBuf = protobufBinding{} - YAML = yamlBinding{} - Uri = uriBinding{} - Header = headerBinding{} -) - -// Default returns the appropriate Binding instance based on the HTTP method -// and the content type. -func Default(method, contentType string) Binding { - if method == "GET" { - return Form - } - - switch contentType { - case MIMEJSON: - return JSON - case MIMEXML, MIMEXML2: - return XML - case MIMEPROTOBUF: - return ProtoBuf - case MIMEYAML: - return YAML - case MIMEMultipartPOSTForm: - return FormMultipart - default: // case MIMEPOSTForm: - return Form - } -} - -func validate(obj interface{}) error { - if Validator == nil { - return nil - } - return Validator.ValidateStruct(obj) -} diff --git a/gin/binding/default_validator.go b/gin/binding/default_validator.go deleted file mode 100644 index 86c79c8..0000000 --- a/gin/binding/default_validator.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2017 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "git.ningdatech.com/ningda/gin_valid/go-playground/locales/zh" - ut "git.ningdatech.com/ningda/gin_valid/go-playground/universal-translator" - zhTrans "git.ningdatech.com/ningda/gin_valid/go-playground/validator/v10/translations/zh" - "reflect" - "strings" - "sync" - - "git.ningdatech.com/ningda/gin_valid/go-playground/validator/v10" -) - -type defaultValidator struct { - once sync.Once - validate *validator.Validate -} - -var _ StructValidator = &defaultValidator{} //这是啥情况?yang - -// ValidateStruct receives any kind of type, but only performed struct or pointer to struct type. -func (v *defaultValidator) ValidateStruct(obj interface{}) error { - value := reflect.ValueOf(obj) - valueType := value.Kind() - if valueType == reflect.Ptr { - valueType = value.Elem().Kind() - } - if valueType == reflect.Struct { - v.lazyinit() - if err := v.validate.Struct(obj); err != nil { - return err - } - } - return nil -} - -// Engine returns the underlying validator engine which powers the default -// Validator instance. This is useful if you want to register custom validations -// or struct level validations. See validator GoDoc for more info - -// https://godoc.org/gopkg.in/go-playground/validator.v8 -func (v *defaultValidator) Engine() interface{} { - v.lazyinit() - return v.validate -} - -var ValidTrans ut.Translator - -func (v *defaultValidator) lazyinit() { - v.once.Do(func() { - v.validate = validator.New() - zh := zh.New() - uni := ut.New(zh, zh) - - // this is usually know or extracted from http 'Accept-Language' header - // also see uni.FindTranslator(...) - ValidTrans, _ = uni.GetTranslator("zh") - - zhTrans.RegisterDefaultTranslations(v.validate, ValidTrans) // 为gin的校验 注册翻译 - v.validate.RegisterTagNameFunc(func(fld reflect.StructField) string { - name := strings.SplitN(fld.Tag.Get("description"), ",", 2)[0] - //if name == "-" { - // return "" - //} - return name - }) - // 设置 tag 的名字 - v.validate.SetTagName("binding") - }) -} diff --git a/gin/binding/form.go b/gin/binding/form.go deleted file mode 100644 index b93c34c..0000000 --- a/gin/binding/form.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "net/http" -) - -const defaultMemory = 32 << 20 - -type formBinding struct{} -type formPostBinding struct{} -type formMultipartBinding struct{} - -func (formBinding) Name() string { - return "form" -} - -func (formBinding) Bind(req *http.Request, obj interface{}) error { - if err := req.ParseForm(); err != nil { - return err - } - if err := req.ParseMultipartForm(defaultMemory); err != nil { - if err != http.ErrNotMultipart { - return err - } - } - if err := mapForm(obj, req.Form); err != nil { - return err - } - return validate(obj) -} - -func (formPostBinding) Name() string { - return "form-urlencoded" -} - -func (formPostBinding) Bind(req *http.Request, obj interface{}) error { - if err := req.ParseForm(); err != nil { - return err - } - if err := mapForm(obj, req.PostForm); err != nil { - return err - } - return validate(obj) -} - -func (formMultipartBinding) Name() string { - return "multipart/form-data" -} - -func (formMultipartBinding) Bind(req *http.Request, obj interface{}) error { - if err := req.ParseMultipartForm(defaultMemory); err != nil { - return err - } - if err := mappingByPtr(obj, (*multipartRequest)(req), "form"); err != nil { - return err - } - - return validate(obj) -} diff --git a/gin/binding/form_mapping.go b/gin/binding/form_mapping.go deleted file mode 100644 index b6d15e0..0000000 --- a/gin/binding/form_mapping.go +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "errors" - "fmt" - "reflect" - "strconv" - "strings" - "time" - - "git.ningdatech.com/ningda/gin_valid/gin/internal/bytesconv" - "git.ningdatech.com/ningda/gin_valid/gin/internal/json" -) - -var errUnknownType = errors.New("unknown type") - -func mapUri(ptr interface{}, m map[string][]string) error { - return mapFormByTag(ptr, m, "uri") -} - -func mapForm(ptr interface{}, form map[string][]string) error { - return mapFormByTag(ptr, form, "form") -} - -var emptyField = reflect.StructField{} - -func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error { - // Check if ptr is a map - ptrVal := reflect.ValueOf(ptr) - var pointed interface{} - if ptrVal.Kind() == reflect.Ptr { - ptrVal = ptrVal.Elem() - pointed = ptrVal.Interface() - } - if ptrVal.Kind() == reflect.Map && - ptrVal.Type().Key().Kind() == reflect.String { - if pointed != nil { - ptr = pointed - } - return setFormMap(ptr, form) - } - - return mappingByPtr(ptr, formSource(form), tag) -} - -// setter tries to set value on a walking by fields of a struct -type setter interface { - TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error) -} - -type formSource map[string][]string - -var _ setter = formSource(nil) - -// TrySet tries to set a value by request's form source (like map[string][]string) -func (form formSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSetted bool, err error) { - return setByForm(value, field, form, tagValue, opt) -} - -func mappingByPtr(ptr interface{}, setter setter, tag string) error { - _, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag) - return err -} - -func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) { - if field.Tag.Get(tag) == "-" { // just ignoring this field - return false, nil - } - - var vKind = value.Kind() - - if vKind == reflect.Ptr { - var isNew bool - vPtr := value - if value.IsNil() { - isNew = true - vPtr = reflect.New(value.Type().Elem()) - } - isSetted, err := mapping(vPtr.Elem(), field, setter, tag) - if err != nil { - return false, err - } - if isNew && isSetted { - value.Set(vPtr) - } - return isSetted, nil - } - - if vKind != reflect.Struct || !field.Anonymous { - ok, err := tryToSetValue(value, field, setter, tag) - if err != nil { - return false, err - } - if ok { - return true, nil - } - } - - if vKind == reflect.Struct { - tValue := value.Type() - - var isSetted bool - for i := 0; i < value.NumField(); i++ { - sf := tValue.Field(i) - if sf.PkgPath != "" && !sf.Anonymous { // unexported - continue - } - ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag) - if err != nil { - return false, err - } - isSetted = isSetted || ok - } - return isSetted, nil - } - return false, nil -} - -type setOptions struct { - isDefaultExists bool - defaultValue string -} - -func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) { - var tagValue string - var setOpt setOptions - - tagValue = field.Tag.Get(tag) - tagValue, opts := head(tagValue, ",") - - if tagValue == "" { // default value is FieldName - tagValue = field.Name - } - if tagValue == "" { // when field is "emptyField" variable - return false, nil - } - - var opt string - for len(opts) > 0 { - opt, opts = head(opts, ",") - - if k, v := head(opt, "="); k == "default" { - setOpt.isDefaultExists = true - setOpt.defaultValue = v - } - } - - return setter.TrySet(value, field, tagValue, setOpt) -} - -func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSetted bool, err error) { - vs, ok := form[tagValue] - if !ok && !opt.isDefaultExists { - return false, nil - } - - switch value.Kind() { - case reflect.Slice: - if !ok { - vs = []string{opt.defaultValue} - } - return true, setSlice(vs, value, field) - case reflect.Array: - if !ok { - vs = []string{opt.defaultValue} - } - if len(vs) != value.Len() { - return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String()) - } - return true, setArray(vs, value, field) - default: - var val string - if !ok { - val = opt.defaultValue - } - - if len(vs) > 0 { - val = vs[0] - } - return true, setWithProperType(val, value, field) - } -} - -func setWithProperType(val string, value reflect.Value, field reflect.StructField) error { - switch value.Kind() { - case reflect.Int: - return setIntField(val, 0, value) - case reflect.Int8: - return setIntField(val, 8, value) - case reflect.Int16: - return setIntField(val, 16, value) - case reflect.Int32: - return setIntField(val, 32, value) - case reflect.Int64: - switch value.Interface().(type) { - case time.Duration: - return setTimeDuration(val, value, field) - } - return setIntField(val, 64, value) - case reflect.Uint: - return setUintField(val, 0, value) - case reflect.Uint8: - return setUintField(val, 8, value) - case reflect.Uint16: - return setUintField(val, 16, value) - case reflect.Uint32: - return setUintField(val, 32, value) - case reflect.Uint64: - return setUintField(val, 64, value) - case reflect.Bool: - return setBoolField(val, value) - case reflect.Float32: - return setFloatField(val, 32, value) - case reflect.Float64: - return setFloatField(val, 64, value) - case reflect.String: - value.SetString(val) - case reflect.Struct: - switch value.Interface().(type) { - case time.Time: - return setTimeField(val, field, value) - } - return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface()) - case reflect.Map: - return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface()) - default: - return errUnknownType - } - return nil -} - -func setIntField(val string, bitSize int, field reflect.Value) error { - if val == "" { - val = "0" - } - intVal, err := strconv.ParseInt(val, 10, bitSize) - if err == nil { - field.SetInt(intVal) - } - return err -} - -func setUintField(val string, bitSize int, field reflect.Value) error { - if val == "" { - val = "0" - } - uintVal, err := strconv.ParseUint(val, 10, bitSize) - if err == nil { - field.SetUint(uintVal) - } - return err -} - -func setBoolField(val string, field reflect.Value) error { - if val == "" { - val = "false" - } - boolVal, err := strconv.ParseBool(val) - if err == nil { - field.SetBool(boolVal) - } - return err -} - -func setFloatField(val string, bitSize int, field reflect.Value) error { - if val == "" { - val = "0.0" - } - floatVal, err := strconv.ParseFloat(val, bitSize) - if err == nil { - field.SetFloat(floatVal) - } - return err -} - -func setTimeField(val string, structField reflect.StructField, value reflect.Value) error { - timeFormat := structField.Tag.Get("time_format") - if timeFormat == "" { - timeFormat = time.RFC3339 - } - - switch tf := strings.ToLower(timeFormat); tf { - case "unix", "unixnano": - tv, err := strconv.ParseInt(val, 10, 64) - if err != nil { - return err - } - - d := time.Duration(1) - if tf == "unixnano" { - d = time.Second - } - - t := time.Unix(tv/int64(d), tv%int64(d)) - value.Set(reflect.ValueOf(t)) - return nil - - } - - if val == "" { - value.Set(reflect.ValueOf(time.Time{})) - return nil - } - - l := time.Local - if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC { - l = time.UTC - } - - if locTag := structField.Tag.Get("time_location"); locTag != "" { - loc, err := time.LoadLocation(locTag) - if err != nil { - return err - } - l = loc - } - - t, err := time.ParseInLocation(timeFormat, val, l) - if err != nil { - return err - } - - value.Set(reflect.ValueOf(t)) - return nil -} - -func setArray(vals []string, value reflect.Value, field reflect.StructField) error { - for i, s := range vals { - err := setWithProperType(s, value.Index(i), field) - if err != nil { - return err - } - } - return nil -} - -func setSlice(vals []string, value reflect.Value, field reflect.StructField) error { - slice := reflect.MakeSlice(value.Type(), len(vals), len(vals)) - err := setArray(vals, slice, field) - if err != nil { - return err - } - value.Set(slice) - return nil -} - -func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error { - d, err := time.ParseDuration(val) - if err != nil { - return err - } - value.Set(reflect.ValueOf(d)) - return nil -} - -func head(str, sep string) (head string, tail string) { - idx := strings.Index(str, sep) - if idx < 0 { - return str, "" - } - return str[:idx], str[idx+len(sep):] -} - -func setFormMap(ptr interface{}, form map[string][]string) error { - el := reflect.TypeOf(ptr).Elem() - - if el.Kind() == reflect.Slice { - ptrMap, ok := ptr.(map[string][]string) - if !ok { - return errors.New("cannot convert to map slices of strings") - } - for k, v := range form { - ptrMap[k] = v - } - - return nil - } - - ptrMap, ok := ptr.(map[string]string) - if !ok { - return errors.New("cannot convert to map of strings") - } - for k, v := range form { - ptrMap[k] = v[len(v)-1] // pick last - } - - return nil -} diff --git a/gin/binding/header.go b/gin/binding/header.go deleted file mode 100644 index 179ce4e..0000000 --- a/gin/binding/header.go +++ /dev/null @@ -1,34 +0,0 @@ -package binding - -import ( - "net/http" - "net/textproto" - "reflect" -) - -type headerBinding struct{} - -func (headerBinding) Name() string { - return "header" -} - -func (headerBinding) Bind(req *http.Request, obj interface{}) error { - - if err := mapHeader(obj, req.Header); err != nil { - return err - } - - return validate(obj) -} - -func mapHeader(ptr interface{}, h map[string][]string) error { - return mappingByPtr(ptr, headerSource(h), "header") -} - -type headerSource map[string][]string - -var _ setter = headerSource(nil) - -func (hs headerSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSetted bool, err error) { - return setByForm(value, field, hs, textproto.CanonicalMIMEHeaderKey(tagValue), opt) -} diff --git a/gin/binding/json.go b/gin/binding/json.go deleted file mode 100644 index 80b4bce..0000000 --- a/gin/binding/json.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "bytes" - "fmt" - "io" - "net/http" - - "git.ningdatech.com/ningda/gin_valid/gin/internal/json" -) - -// EnableDecoderUseNumber is used to call the UseNumber method on the JSON -// Decoder instance. UseNumber causes the Decoder to unmarshal a number into an -// interface{} as a Number instead of as a float64. -var EnableDecoderUseNumber = false - -// EnableDecoderDisallowUnknownFields is used to call the DisallowUnknownFields method -// on the JSON Decoder instance. DisallowUnknownFields causes the Decoder to -// return an error when the destination is a struct and the input contains object -// keys which do not match any non-ignored, exported fields in the destination. -var EnableDecoderDisallowUnknownFields = false - -type jsonBinding struct{} - -func (jsonBinding) Name() string { - return "json" -} - -func (jsonBinding) Bind(req *http.Request, obj interface{}) error { - if req == nil || req.Body == nil { - return fmt.Errorf("invalid request") - } - return decodeJSON(req.Body, obj) -} - -func (jsonBinding) BindBody(body []byte, obj interface{}) error { - return decodeJSON(bytes.NewReader(body), obj) -} - -func decodeJSON(r io.Reader, obj interface{}) error { - decoder := json.NewDecoder(r) - if EnableDecoderUseNumber { - decoder.UseNumber() - } - if EnableDecoderDisallowUnknownFields { - decoder.DisallowUnknownFields() - } - if err := decoder.Decode(obj); err != nil { - return err - } - return validate(obj) -} diff --git a/gin/binding/msgpack.go b/gin/binding/msgpack.go deleted file mode 100644 index a5bc2ad..0000000 --- a/gin/binding/msgpack.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2017 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -// +build !nomsgpack - -package binding - -import ( - "bytes" - "io" - "net/http" - - "github.com/ugorji/go/codec" -) - -type msgpackBinding struct{} - -func (msgpackBinding) Name() string { - return "msgpack" -} - -func (msgpackBinding) Bind(req *http.Request, obj interface{}) error { - return decodeMsgPack(req.Body, obj) -} - -func (msgpackBinding) BindBody(body []byte, obj interface{}) error { - return decodeMsgPack(bytes.NewReader(body), obj) -} - -func decodeMsgPack(r io.Reader, obj interface{}) error { - cdc := new(codec.MsgpackHandle) - if err := codec.NewDecoder(r, cdc).Decode(&obj); err != nil { - return err - } - return validate(obj) -} diff --git a/gin/binding/multipart_form_mapping.go b/gin/binding/multipart_form_mapping.go deleted file mode 100644 index f85a1aa..0000000 --- a/gin/binding/multipart_form_mapping.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2019 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "errors" - "mime/multipart" - "net/http" - "reflect" -) - -type multipartRequest http.Request - -var _ setter = (*multipartRequest)(nil) - -// TrySet tries to set a value by the multipart request with the binding a form file -func (r *multipartRequest) TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error) { - if files := r.MultipartForm.File[key]; len(files) != 0 { - return setByMultipartFormFile(value, field, files) - } - - return setByForm(value, field, r.MultipartForm.Value, key, opt) -} - -func setByMultipartFormFile(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (isSetted bool, err error) { - switch value.Kind() { - case reflect.Ptr: - switch value.Interface().(type) { - case *multipart.FileHeader: - value.Set(reflect.ValueOf(files[0])) - return true, nil - } - case reflect.Struct: - switch value.Interface().(type) { - case multipart.FileHeader: - value.Set(reflect.ValueOf(*files[0])) - return true, nil - } - case reflect.Slice: - slice := reflect.MakeSlice(value.Type(), len(files), len(files)) - isSetted, err = setArrayOfMultipartFormFiles(slice, field, files) - if err != nil || !isSetted { - return isSetted, err - } - value.Set(slice) - return true, nil - case reflect.Array: - return setArrayOfMultipartFormFiles(value, field, files) - } - return false, errors.New("unsupported field type for multipart.FileHeader") -} - -func setArrayOfMultipartFormFiles(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (isSetted bool, err error) { - if value.Len() != len(files) { - return false, errors.New("unsupported len of array for []*multipart.FileHeader") - } - for i := range files { - setted, err := setByMultipartFormFile(value.Index(i), field, files[i:i+1]) - if err != nil || !setted { - return setted, err - } - } - return true, nil -} diff --git a/gin/binding/protobuf.go b/gin/binding/protobuf.go deleted file mode 100644 index f9ece92..0000000 --- a/gin/binding/protobuf.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "io/ioutil" - "net/http" - - "github.com/golang/protobuf/proto" -) - -type protobufBinding struct{} - -func (protobufBinding) Name() string { - return "protobuf" -} - -func (b protobufBinding) Bind(req *http.Request, obj interface{}) error { - buf, err := ioutil.ReadAll(req.Body) - if err != nil { - return err - } - return b.BindBody(buf, obj) -} - -func (protobufBinding) BindBody(body []byte, obj interface{}) error { - if err := proto.Unmarshal(body, obj.(proto.Message)); err != nil { - return err - } - // Here it's same to return validate(obj), but util now we can't add - // `binding:""` to the struct which automatically generate by gen-proto - return nil - // return validate(obj) -} diff --git a/gin/binding/query.go b/gin/binding/query.go deleted file mode 100644 index 219743f..0000000 --- a/gin/binding/query.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2017 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import "net/http" - -type queryBinding struct{} - -func (queryBinding) Name() string { - return "query" -} - -func (queryBinding) Bind(req *http.Request, obj interface{}) error { - values := req.URL.Query() - if err := mapForm(obj, values); err != nil { - return err - } - return validate(obj) -} diff --git a/gin/binding/uri.go b/gin/binding/uri.go deleted file mode 100644 index f91ec38..0000000 --- a/gin/binding/uri.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -type uriBinding struct{} - -func (uriBinding) Name() string { - return "uri" -} - -func (uriBinding) BindUri(m map[string][]string, obj interface{}) error { - if err := mapUri(obj, m); err != nil { - return err - } - return validate(obj) -} diff --git a/gin/binding/xml.go b/gin/binding/xml.go deleted file mode 100644 index 4e90114..0000000 --- a/gin/binding/xml.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2014 Manu Martinez-Almeida. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "bytes" - "encoding/xml" - "io" - "net/http" -) - -type xmlBinding struct{} - -func (xmlBinding) Name() string { - return "xml" -} - -func (xmlBinding) Bind(req *http.Request, obj interface{}) error { - return decodeXML(req.Body, obj) -} - -func (xmlBinding) BindBody(body []byte, obj interface{}) error { - return decodeXML(bytes.NewReader(body), obj) -} -func decodeXML(r io.Reader, obj interface{}) error { - decoder := xml.NewDecoder(r) - if err := decoder.Decode(obj); err != nil { - return err - } - return validate(obj) -} diff --git a/gin/binding/yaml.go b/gin/binding/yaml.go deleted file mode 100644 index a2d36d6..0000000 --- a/gin/binding/yaml.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package binding - -import ( - "bytes" - "io" - "net/http" - - "gopkg.in/yaml.v2" -) - -type yamlBinding struct{} - -func (yamlBinding) Name() string { - return "yaml" -} - -func (yamlBinding) Bind(req *http.Request, obj interface{}) error { - return decodeYAML(req.Body, obj) -} - -func (yamlBinding) BindBody(body []byte, obj interface{}) error { - return decodeYAML(bytes.NewReader(body), obj) -} - -func decodeYAML(r io.Reader, obj interface{}) error { - decoder := yaml.NewDecoder(r) - if err := decoder.Decode(obj); err != nil { - return err - } - return validate(obj) -} diff --git a/gin/internal/bytesconv/bytesconv.go b/gin/internal/bytesconv/bytesconv.go deleted file mode 100644 index 7b80e33..0000000 --- a/gin/internal/bytesconv/bytesconv.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2020 Gin Core Team. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -package bytesconv - -import ( - "reflect" - "unsafe" -) - -// StringToBytes converts string to byte slice without a memory allocation. -func StringToBytes(s string) (b []byte) { - sh := *(*reflect.StringHeader)(unsafe.Pointer(&s)) - bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) - bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len - return b -} - -// BytesToString converts byte slice to string without a memory allocation. -func BytesToString(b []byte) string { - return *(*string)(unsafe.Pointer(&b)) -} diff --git a/gin/internal/json/json.go b/gin/internal/json/json.go deleted file mode 100644 index 480e8bf..0000000 --- a/gin/internal/json/json.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2017 Bo-Yi Wu. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -// +build !jsoniter - -package json - -import "encoding/json" - -var ( - // Marshal is exported by gin/json package. - Marshal = json.Marshal - // Unmarshal is exported by gin/json package. - Unmarshal = json.Unmarshal - // MarshalIndent is exported by gin/json package. - MarshalIndent = json.MarshalIndent - // NewDecoder is exported by gin/json package. - NewDecoder = json.NewDecoder - // NewEncoder is exported by gin/json package. - NewEncoder = json.NewEncoder -) diff --git a/gin/internal/json/jsoniter.go b/gin/internal/json/jsoniter.go deleted file mode 100644 index 649a3cd..0000000 --- a/gin/internal/json/jsoniter.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017 Bo-Yi Wu. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -// +build jsoniter - -package json - -import jsoniter "github.com/json-iterator/go" - -var ( - json = jsoniter.ConfigCompatibleWithStandardLibrary - // Marshal is exported by gin/json package. - Marshal = json.Marshal - // Unmarshal is exported by gin/json package. - Unmarshal = json.Unmarshal - // MarshalIndent is exported by gin/json package. - MarshalIndent = json.MarshalIndent - // NewDecoder is exported by gin/json package. - NewDecoder = json.NewDecoder - // NewEncoder is exported by gin/json package. - NewEncoder = json.NewEncoder -) diff --git a/go-playground/locales/.gitignore b/go-playground/locales/.gitignore deleted file mode 100644 index daf913b..0000000 --- a/go-playground/locales/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof diff --git a/go-playground/locales/.travis.yml b/go-playground/locales/.travis.yml deleted file mode 100644 index d50237a..0000000 --- a/go-playground/locales/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: go -go: - - 1.13.1 - - tip -matrix: - allow_failures: - - go: tip - -notifications: - email: - recipients: dean.karn@gmail.com - on_success: change - on_failure: always - -before_install: - - go install github.com/mattn/goveralls - -# Only clone the most recent commit. -git: - depth: 1 - -script: - - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./... - -after_success: | - goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN \ No newline at end of file diff --git a/go-playground/locales/LICENSE b/go-playground/locales/LICENSE deleted file mode 100644 index 75854ac..0000000 --- a/go-playground/locales/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Go Playground - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/go-playground/locales/README.md b/go-playground/locales/README.md deleted file mode 100644 index ba1b068..0000000 --- a/go-playground/locales/README.md +++ /dev/null @@ -1,172 +0,0 @@ -## locales -![Project status](https://img.shields.io/badge/version-0.13.0-green.svg) -[![Build Status](https://travis-ci.org/go-playground/locales.svg?branch=master)](https://travis-ci.org/go-playground/locales) -[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/locales)](https://goreportcard.com/report/github.com/go-playground/locales) -[![GoDoc](https://godoc.org/github.com/go-playground/locales?status.svg)](https://godoc.org/github.com/go-playground/locales) -![License](https://img.shields.io/dub/l/vibe-d.svg) -[![Gitter](https://badges.gitter.im/go-playground/locales.svg)](https://gitter.im/go-playground/locales?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - -Locales is a set of locales generated from the [Unicode CLDR Project](http://cldr.unicode.org/) which can be used independently or within -an i18n package; these were built for use with, but not exclusive to, [Universal Translator](https://github.com/go-playground/universal-translator). - -Features --------- -- [x] Rules generated from the latest [CLDR](http://cldr.unicode.org/index/downloads) data, v31.0.1 -- [x] Contains Cardinal, Ordinal and Range Plural Rules -- [x] Contains Month, Weekday and Timezone translations built in -- [x] Contains Date & Time formatting functions -- [x] Contains Number, Currency, Accounting and Percent formatting functions -- [x] Supports the "Gregorian" calendar only ( my time isn't unlimited, had to draw the line somewhere ) - -Full Tests --------------------- -I could sure use your help adding tests for every locale, it is a huge undertaking and I just don't have the free time to do it all at the moment; -any help would be **greatly appreciated!!!!** please see [issue](https://github.com/go-playground/locales/issues/1) for details. - -Installation ------------ - -Use go get - -```shell -go get github.com/go-playground/locales -``` - -NOTES --------- -You'll notice most return types are []byte, this is because most of the time the results will be concatenated with a larger body -of text and can avoid some allocations if already appending to a byte array, otherwise just cast as string. - -Usage -------- -```go -package main - -import ( - "fmt" - "time" - - "github.com/go-playground/locales/currency" - "github.com/go-playground/locales/en_CA" -) - -func main() { - - loc, _ := time.LoadLocation("America/Toronto") - datetime := time.Date(2016, 02, 03, 9, 0, 1, 0, loc) - - l := en_CA.New() - - // Dates - fmt.Println(l.FmtDateFull(datetime)) - fmt.Println(l.FmtDateLong(datetime)) - fmt.Println(l.FmtDateMedium(datetime)) - fmt.Println(l.FmtDateShort(datetime)) - - // Times - fmt.Println(l.FmtTimeFull(datetime)) - fmt.Println(l.FmtTimeLong(datetime)) - fmt.Println(l.FmtTimeMedium(datetime)) - fmt.Println(l.FmtTimeShort(datetime)) - - // Months Wide - fmt.Println(l.MonthWide(time.January)) - fmt.Println(l.MonthWide(time.February)) - fmt.Println(l.MonthWide(time.March)) - // ... - - // Months Abbreviated - fmt.Println(l.MonthAbbreviated(time.January)) - fmt.Println(l.MonthAbbreviated(time.February)) - fmt.Println(l.MonthAbbreviated(time.March)) - // ... - - // Months Narrow - fmt.Println(l.MonthNarrow(time.January)) - fmt.Println(l.MonthNarrow(time.February)) - fmt.Println(l.MonthNarrow(time.March)) - // ... - - // Weekdays Wide - fmt.Println(l.WeekdayWide(time.Sunday)) - fmt.Println(l.WeekdayWide(time.Monday)) - fmt.Println(l.WeekdayWide(time.Tuesday)) - // ... - - // Weekdays Abbreviated - fmt.Println(l.WeekdayAbbreviated(time.Sunday)) - fmt.Println(l.WeekdayAbbreviated(time.Monday)) - fmt.Println(l.WeekdayAbbreviated(time.Tuesday)) - // ... - - // Weekdays Short - fmt.Println(l.WeekdayShort(time.Sunday)) - fmt.Println(l.WeekdayShort(time.Monday)) - fmt.Println(l.WeekdayShort(time.Tuesday)) - // ... - - // Weekdays Narrow - fmt.Println(l.WeekdayNarrow(time.Sunday)) - fmt.Println(l.WeekdayNarrow(time.Monday)) - fmt.Println(l.WeekdayNarrow(time.Tuesday)) - // ... - - var f64 float64 - - f64 = -10356.4523 - - // Number - fmt.Println(l.FmtNumber(f64, 2)) - - // Currency - fmt.Println(l.FmtCurrency(f64, 2, currency.CAD)) - fmt.Println(l.FmtCurrency(f64, 2, currency.USD)) - - // Accounting - fmt.Println(l.FmtAccounting(f64, 2, currency.CAD)) - fmt.Println(l.FmtAccounting(f64, 2, currency.USD)) - - f64 = 78.12 - - // Percent - fmt.Println(l.FmtPercent(f64, 0)) - - // Plural Rules for locale, so you know what rules you must cover - fmt.Println(l.PluralsCardinal()) - fmt.Println(l.PluralsOrdinal()) - - // Cardinal Plural Rules - fmt.Println(l.CardinalPluralRule(1, 0)) - fmt.Println(l.CardinalPluralRule(1.0, 0)) - fmt.Println(l.CardinalPluralRule(1.0, 1)) - fmt.Println(l.CardinalPluralRule(3, 0)) - - // Ordinal Plural Rules - fmt.Println(l.OrdinalPluralRule(21, 0)) // 21st - fmt.Println(l.OrdinalPluralRule(22, 0)) // 22nd - fmt.Println(l.OrdinalPluralRule(33, 0)) // 33rd - fmt.Println(l.OrdinalPluralRule(34, 0)) // 34th - - // Range Plural Rules - fmt.Println(l.RangePluralRule(1, 0, 1, 0)) // 1-1 - fmt.Println(l.RangePluralRule(1, 0, 2, 0)) // 1-2 - fmt.Println(l.RangePluralRule(5, 0, 8, 0)) // 5-8 -} -``` - -NOTES: -------- -These rules were generated from the [Unicode CLDR Project](http://cldr.unicode.org/), if you encounter any issues -I strongly encourage contributing to the CLDR project to get the locale information corrected and the next time -these locales are regenerated the fix will come with. - -I do however realize that time constraints are often important and so there are two options: - -1. Create your own locale, copy, paste and modify, and ensure it complies with the `Translator` interface. -2. Add an exception in the locale generation code directly and once regenerated, fix will be in place. - -Please to not make fixes inside the locale files, they WILL get overwritten when the locales are regenerated. - -License ------- -Distributed under MIT License, please see license file in code for more details. diff --git a/go-playground/locales/currency/currency.go b/go-playground/locales/currency/currency.go deleted file mode 100644 index cdaba59..0000000 --- a/go-playground/locales/currency/currency.go +++ /dev/null @@ -1,308 +0,0 @@ -package currency - -// Type is the currency type associated with the locales currency enum -type Type int - -// locale currencies -const ( - ADP Type = iota - AED - AFA - AFN - ALK - ALL - AMD - ANG - AOA - AOK - AON - AOR - ARA - ARL - ARM - ARP - ARS - ATS - AUD - AWG - AZM - AZN - BAD - BAM - BAN - BBD - BDT - BEC - BEF - BEL - BGL - BGM - BGN - BGO - BHD - BIF - BMD - BND - BOB - BOL - BOP - BOV - BRB - BRC - BRE - BRL - BRN - BRR - BRZ - BSD - BTN - BUK - BWP - BYB - BYN - BYR - BZD - CAD - CDF - CHE - CHF - CHW - CLE - CLF - CLP - CNH - CNX - CNY - COP - COU - CRC - CSD - CSK - CUC - CUP - CVE - CYP - CZK - DDM - DEM - DJF - DKK - DOP - DZD - ECS - ECV - EEK - EGP - ERN - ESA - ESB - ESP - ETB - EUR - FIM - FJD - FKP - FRF - GBP - GEK - GEL - GHC - GHS - GIP - GMD - GNF - GNS - GQE - GRD - GTQ - GWE - GWP - GYD - HKD - HNL - HRD - HRK - HTG - HUF - IDR - IEP - ILP - ILR - ILS - INR - IQD - IRR - ISJ - ISK - ITL - JMD - JOD - JPY - KES - KGS - KHR - KMF - KPW - KRH - KRO - KRW - KWD - KYD - KZT - LAK - LBP - LKR - LRD - LSL - LTL - LTT - LUC - LUF - LUL - LVL - LVR - LYD - MAD - MAF - MCF - MDC - MDL - MGA - MGF - MKD - MKN - MLF - MMK - MNT - MOP - MRO - MTL - MTP - MUR - MVP - MVR - MWK - MXN - MXP - MXV - MYR - MZE - MZM - MZN - NAD - NGN - NIC - NIO - NLG - NOK - NPR - NZD - OMR - PAB - PEI - PEN - PES - PGK - PHP - PKR - PLN - PLZ - PTE - PYG - QAR - RHD - ROL - RON - RSD - RUB - RUR - RWF - SAR - SBD - SCR - SDD - SDG - SDP - SEK - SGD - SHP - SIT - SKK - SLL - SOS - SRD - SRG - SSP - STD - STN - SUR - SVC - SYP - SZL - THB - TJR - TJS - TMM - TMT - TND - TOP - TPE - TRL - TRY - TTD - TWD - TZS - UAH - UAK - UGS - UGX - USD - USN - USS - UYI - UYP - UYU - UZS - VEB - VEF - VND - VNN - VUV - WST - XAF - XAG - XAU - XBA - XBB - XBC - XBD - XCD - XDR - XEU - XFO - XFU - XOF - XPD - XPF - XPT - XRE - XSU - XTS - XUA - XXX - YDD - YER - YUD - YUM - YUN - YUR - ZAL - ZAR - ZMK - ZMW - ZRN - ZRZ - ZWD - ZWL - ZWR -) diff --git a/go-playground/locales/logo.png b/go-playground/locales/logo.png deleted file mode 100644 index 3038276..0000000 Binary files a/go-playground/locales/logo.png and /dev/null differ diff --git a/go-playground/locales/rules.go b/go-playground/locales/rules.go deleted file mode 100644 index 6fd1b93..0000000 --- a/go-playground/locales/rules.go +++ /dev/null @@ -1,293 +0,0 @@ -package locales - -import ( - "strconv" - "time" - - "git.ningdatech.com/ningda/gin_valid/go-playground/locales/currency" -) - -// // ErrBadNumberValue is returned when the number passed for -// // plural rule determination cannot be parsed -// type ErrBadNumberValue struct { -// NumberValue string -// InnerError error -// } - -// // Error returns ErrBadNumberValue error string -// func (e *ErrBadNumberValue) Error() string { -// return fmt.Sprintf("Invalid Number Value '%s' %s", e.NumberValue, e.InnerError) -// } - -// var _ error = new(ErrBadNumberValue) - -// PluralRule denotes the type of plural rules -type PluralRule int - -// PluralRule's -const ( - PluralRuleUnknown PluralRule = iota - PluralRuleZero // zero - PluralRuleOne // one - singular - PluralRuleTwo // two - dual - PluralRuleFew // few - paucal - PluralRuleMany // many - also used for fractions if they have a separate class - PluralRuleOther // other - required—general plural form—also used if the language only has a single form -) - -const ( - pluralsString = "UnknownZeroOneTwoFewManyOther" -) - -// Translator encapsulates an instance of a locale -// NOTE: some values are returned as a []byte just in case the caller -// wishes to add more and can help avoid allocations; otherwise just cast as string -type Translator interface { - - // The following Functions are for overriding, debugging or developing - // with a Translator Locale - - // Locale returns the string value of the translator - Locale() string - - // returns an array of cardinal plural rules associated - // with this translator - PluralsCardinal() []PluralRule - - // returns an array of ordinal plural rules associated - // with this translator - PluralsOrdinal() []PluralRule - - // returns an array of range plural rules associated - // with this translator - PluralsRange() []PluralRule - - // returns the cardinal PluralRule given 'num' and digits/precision of 'v' for locale - CardinalPluralRule(num float64, v uint64) PluralRule - - // returns the ordinal PluralRule given 'num' and digits/precision of 'v' for locale - OrdinalPluralRule(num float64, v uint64) PluralRule - - // returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for locale - RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) PluralRule - - // returns the locales abbreviated month given the 'month' provided - MonthAbbreviated(month time.Month) string - - // returns the locales abbreviated months - MonthsAbbreviated() []string - - // returns the locales narrow month given the 'month' provided - MonthNarrow(month time.Month) string - - // returns the locales narrow months - MonthsNarrow() []string - - // returns the locales wide month given the 'month' provided - MonthWide(month time.Month) string - - // returns the locales wide months - MonthsWide() []string - - // returns the locales abbreviated weekday given the 'weekday' provided - WeekdayAbbreviated(weekday time.Weekday) string - - // returns the locales abbreviated weekdays - WeekdaysAbbreviated() []string - - // returns the locales narrow weekday given the 'weekday' provided - WeekdayNarrow(weekday time.Weekday) string - - // WeekdaysNarrowreturns the locales narrow weekdays - WeekdaysNarrow() []string - - // returns the locales short weekday given the 'weekday' provided - WeekdayShort(weekday time.Weekday) string - - // returns the locales short weekdays - WeekdaysShort() []string - - // returns the locales wide weekday given the 'weekday' provided - WeekdayWide(weekday time.Weekday) string - - // returns the locales wide weekdays - WeekdaysWide() []string - - // The following Functions are common Formatting functionsfor the Translator's Locale - - // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v' - FmtNumber(num float64, v uint64) string - - // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v' - // NOTE: 'num' passed into FmtPercent is assumed to be in percent already - FmtPercent(num float64, v uint64) string - - // returns the currency representation of 'num' with digits/precision of 'v' for locale - FmtCurrency(num float64, v uint64, currency currency.Type) string - - // returns the currency representation of 'num' with digits/precision of 'v' for locale - // in accounting notation. - FmtAccounting(num float64, v uint64, currency currency.Type) string - - // returns the short date representation of 't' for locale - FmtDateShort(t time.Time) string - - // returns the medium date representation of 't' for locale - FmtDateMedium(t time.Time) string - - // returns the long date representation of 't' for locale - FmtDateLong(t time.Time) string - - // returns the full date representation of 't' for locale - FmtDateFull(t time.Time) string - - // returns the short time representation of 't' for locale - FmtTimeShort(t time.Time) string - - // returns the medium time representation of 't' for locale - FmtTimeMedium(t time.Time) string - - // returns the long time representation of 't' for locale - FmtTimeLong(t time.Time) string - - // returns the full time representation of 't' for locale - FmtTimeFull(t time.Time) string -} - -// String returns the string value of PluralRule -func (p PluralRule) String() string { - - switch p { - case PluralRuleZero: - return pluralsString[7:11] - case PluralRuleOne: - return pluralsString[11:14] - case PluralRuleTwo: - return pluralsString[14:17] - case PluralRuleFew: - return pluralsString[17:20] - case PluralRuleMany: - return pluralsString[20:24] - case PluralRuleOther: - return pluralsString[24:] - default: - return pluralsString[:7] - } -} - -// -// Precision Notes: -// -// must specify a precision >= 0, and here is why https://play.golang.org/p/LyL90U0Vyh -// -// v := float64(3.141) -// i := float64(int64(v)) -// -// fmt.Println(v - i) -// -// or -// -// s := strconv.FormatFloat(v-i, 'f', -1, 64) -// fmt.Println(s) -// -// these will not print what you'd expect: 0.14100000000000001 -// and so this library requires a precision to be specified, or -// inaccurate plural rules could be applied. -// -// -// -// n - absolute value of the source number (integer and decimals). -// i - integer digits of n. -// v - number of visible fraction digits in n, with trailing zeros. -// w - number of visible fraction digits in n, without trailing zeros. -// f - visible fractional digits in n, with trailing zeros. -// t - visible fractional digits in n, without trailing zeros. -// -// -// Func(num float64, v uint64) // v = digits/precision and prevents -1 as a special case as this can lead to very unexpected behaviour, see precision note's above. -// -// n := math.Abs(num) -// i := int64(n) -// v := v -// -// -// w := strconv.FormatFloat(num-float64(i), 'f', int(v), 64) // then parse backwards on string until no more zero's.... -// f := strconv.FormatFloat(n, 'f', int(v), 64) // then turn everything after decimal into an int64 -// t := strconv.FormatFloat(n, 'f', int(v), 64) // then parse backwards on string until no more zero's.... -// -// -// -// General Inclusion Rules -// - v will always be available inherently -// - all require n -// - w requires i -// - -// W returns the number of visible fraction digits in N, without trailing zeros. -func W(n float64, v uint64) (w int64) { - - s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) - - // with either be '0' or '0.xxxx', so if 1 then w will be zero - // otherwise need to parse - if len(s) != 1 { - - s = s[2:] - end := len(s) + 1 - - for i := end; i >= 0; i-- { - if s[i] != '0' { - end = i + 1 - break - } - } - - w = int64(len(s[:end])) - } - - return -} - -// F returns the visible fractional digits in N, with trailing zeros. -func F(n float64, v uint64) (f int64) { - - s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) - - // with either be '0' or '0.xxxx', so if 1 then f will be zero - // otherwise need to parse - if len(s) != 1 { - - // ignoring error, because it can't fail as we generated - // the string internally from a real number - f, _ = strconv.ParseInt(s[2:], 10, 64) - } - - return -} - -// T returns the visible fractional digits in N, without trailing zeros. -func T(n float64, v uint64) (t int64) { - - s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) - - // with either be '0' or '0.xxxx', so if 1 then t will be zero - // otherwise need to parse - if len(s) != 1 { - - s = s[2:] - end := len(s) + 1 - - for i := end; i >= 0; i-- { - if s[i] != '0' { - end = i + 1 - break - } - } - - // ignoring error, because it can't fail as we generated - // the string internally from a real number - t, _ = strconv.ParseInt(s[:end], 10, 64) - } - - return -} diff --git a/go-playground/locales/zh/zh.go b/go-playground/locales/zh/zh.go deleted file mode 100644 index 9672a78..0000000 --- a/go-playground/locales/zh/zh.go +++ /dev/null @@ -1,619 +0,0 @@ -package zh - -import ( - "math" - "strconv" - "time" - - "git.ningdatech.com/ningda/gin_valid/go-playground/locales" - "git.ningdatech.com/ningda/gin_valid/go-playground/locales/currency" -) - -type zh struct { - locale string - pluralsCardinal []locales.PluralRule - pluralsOrdinal []locales.PluralRule - pluralsRange []locales.PluralRule - decimal string - group string - minus string - percent string - perMille string - timeSeparator string - inifinity string - currencies []string // idx = enum of currency code - monthsAbbreviated []string - monthsNarrow []string - monthsWide []string - daysAbbreviated []string - daysNarrow []string - daysShort []string - daysWide []string - periodsAbbreviated []string - periodsNarrow []string - periodsShort []string - periodsWide []string - erasAbbreviated []string - erasNarrow []string - erasWide []string - timezones map[string]string -} - -// New returns a new instance of translator for the 'zh' locale -func New() locales.Translator { - return &zh{ - locale: "zh", - pluralsCardinal: []locales.PluralRule{6}, - pluralsOrdinal: []locales.PluralRule{6}, - pluralsRange: []locales.PluralRule{6}, - decimal: ".", - group: ",", - minus: "-", - percent: "%", - perMille: "‰", - timeSeparator: ":", - inifinity: "∞", - currencies: []string{"ADP", "AED", "AFA", "AFN", "ALK", "ALL", "AMD", "ANG", "AOA", "AOK", "AON", "AOR", "ARA", "ARL", "ARM", "ARP", "ARS", "ATS", "AU$", "AWG", "AZM", "AZN", "BAD", "BAM", "BAN", "BBD", "BDT", "BEC", "BEF", "BEL", "BGL", "BGM", "BGN", "BGO", "BHD", "BIF", "BMD", "BND", "BOB", "BOL", "BOP", "BOV", "BRB", "BRC", "BRE", "R$", "BRN", "BRR", "BRZ", "BSD", "BTN", "BUK", "BWP", "BYB", "BYN", "BYR", "BZD", "CA$", "CDF", "CHE", "CHF", "CHW", "CLE", "CLF", "CLP", "CNH", "CNX", "¥", "COP", "COU", "CRC", "CSD", "CSK", "CUC", "CUP", "CVE", "CYP", "CZK", "DDM", "DEM", "DJF", "DKK", "DOP", "DZD", "ECS", "ECV", "EEK", "EGP", "ERN", "ESA", "ESB", "ESP", "ETB", "€", "FIM", "FJD", "FKP", "FRF", "£", "GEK", "GEL", "GHC", "GHS", "GIP", "GMD", "GNF", "GNS", "GQE", "GRD", "GTQ", "GWE", "GWP", "GYD", "HK$", "HNL", "HRD", "HRK", "HTG", "HUF", "IDR", "IEP", "ILP", "ILS", "₪", "₹", "IQD", "IRR", "ISJ", "ISK", "ITL", "JMD", "JOD", "JP¥", "KES", "KGS", "KHR", "KMF", "KPW", "KRH", "KRO", "₩", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LTL", "LTT", "LUC", "LUF", "LUL", "LVL", "LVR", "LYD", "MAD", "MAF", "MCF", "MDC", "MDL", "MGA", "MGF", "MKD", "MKN", "MLF", "MMK", "MNT", "MOP", "MRO", "MTL", "MTP", "MUR", "MVP", "MVR", "MWK", "MX$", "MXP", "MXV", "MYR", "MZE", "MZM", "MZN", "NAD", "NGN", "NIC", "NIO", "NLG", "NOK", "NPR", "NZ$", "OMR", "PAB", "PEI", "PEN", "PES", "PGK", "PHP", "PKR", "PLN", "PLZ", "PTE", "PYG", "QAR", "RHD", "ROL", "RON", "RSD", "RUB", "RUR", "RWF", "SAR", "SBD", "SCR", "SDD", "SDG", "SDP", "SEK", "SGD", "SHP", "SIT", "SKK", "SLL", "SOS", "SRD", "SRG", "SSP", "STD", "STN", "SUR", "SVC", "SYP", "SZL", "THB", "TJR", "TJS", "TMM", "TMT", "TND", "TOP", "TPE", "TRL", "TRY", "TTD", "NT$", "TZS", "UAH", "UAK", "UGS", "UGX", "US$", "USN", "USS", "UYI", "UYP", "UYU", "UZS", "VEB", "VEF", "₫", "VNN", "VUV", "WST", "FCFA", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "EC$", "XDR", "XEU", "XFO", "XFU", "CFA", "XPD", "CFPF", "XPT", "XRE", "XSU", "XTS", "XUA", "XXX", "YDD", "YER", "YUD", "YUM", "YUN", "YUR", "ZAL", "ZAR", "ZMK", "ZMW", "ZRN", "ZRZ", "ZWD", "ZWL", "ZWR"}, - monthsAbbreviated: []string{"", "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"}, - monthsNarrow: []string{"", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"}, - monthsWide: []string{"", "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"}, - daysAbbreviated: []string{"周日", "周一", "周二", "周三", "周四", "周五", "周六"}, - daysNarrow: []string{"日", "一", "二", "三", "四", "五", "六"}, - daysShort: []string{"周日", "周一", "周二", "周三", "周四", "周五", "周六"}, - daysWide: []string{"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}, - periodsAbbreviated: []string{"上午", "下午"}, - periodsNarrow: []string{"上午", "下午"}, - periodsWide: []string{"上午", "下午"}, - erasAbbreviated: []string{"公元前", "公元"}, - erasNarrow: []string{"公元前", "公元"}, - erasWide: []string{"公元前", "公元"}, - timezones: map[string]string{"UYST": "乌拉圭夏令时间", "HNPMX": "墨西哥太平洋标准时间", "MDT": "北美山区夏令时间", "WESZ": "西欧夏令时间", "AKST": "阿拉斯加标准时间", "ACWST": "澳大利亚中西部标准时间", "HENOMX": "墨西哥西北部夏令时间", "WIT": "印度尼西亚东部时间", "HEPMX": "墨西哥太平洋夏令时间", "JST": "日本标准时间", "SRT": "苏里南时间", "CLST": "智利夏令时间", "UYT": "乌拉圭标准时间", "AWDT": "澳大利亚西部夏令时间", "MST": "北美山区标准时间", "WAST": "西部非洲夏令时间", "NZST": "新西兰标准时间", "EAT": "东部非洲时间", "HECU": "古巴夏令时间", "BT": "不丹时间", "EDT": "北美东部夏令时间", "WARST": "阿根廷西部夏令时间", "HNPM": "圣皮埃尔和密克隆群岛标准时间", "HNCU": "古巴标准时间", "PDT": "北美太平洋夏令时间", "LHDT": "豪勋爵岛夏令时间", "CLT": "智利标准时间", "PST": "北美太平洋标准时间", "JDT": "日本夏令时间", "OEZ": "东欧标准时间", "TMT": "土库曼斯坦标准时间", "CST": "北美中部标准时间", "AWST": "澳大利亚西部标准时间", "AEST": "澳大利亚东部标准时间", "AKDT": "阿拉斯加夏令时间", "HKT": "香港标准时间", "LHST": "豪勋爵岛标准时间", "HNNOMX": "墨西哥西北部标准时间", "BOT": "玻利维亚标准时间", "HNOG": "格陵兰岛西部标准时间", "EST": "北美东部标准时间", "MESZ": "中欧夏令时间", "WITA": "印度尼西亚中部时间", "CAT": "中部非洲时间", "COST": "哥伦比亚夏令时间", "CHADT": "查坦夏令时间", "AST": "大西洋标准时间", "MYT": "马来西亚时间", "OESZ": "东欧夏令时间", "COT": "哥伦比亚标准时间", "SAST": "南非标准时间", "HEOG": "格陵兰岛西部夏令时间", "ACWDT": "澳大利亚中西部夏令时间", "MEZ": "中欧标准时间", "GYT": "圭亚那时间", "ADT": "大西洋夏令时间", "HEEG": "格陵兰岛东部夏令时间", "WART": "阿根廷西部标准时间", "VET": "委内瑞拉时间", "GMT": "格林尼治标准时间", "∅∅∅": "巴西利亚夏令时间", "SGT": "新加坡标准时间", "ACDT": "澳大利亚中部夏令时间", "HAT": "纽芬兰夏令时间", "HADT": "夏威夷-阿留申夏令时间", "CHAST": "查坦标准时间", "CDT": "北美中部夏令时间", "AEDT": "澳大利亚东部夏令时间", "WEZ": "西欧标准时间", "NZDT": "新西兰夏令时间", "ECT": "厄瓜多尔标准时间", "GFT": "法属圭亚那标准时间", "HKST": "香港夏令时间", "IST": "印度时间", "HNT": "纽芬兰标准时间", "ART": "阿根廷标准时间", "ChST": "查莫罗时间", "WAT": "西部非洲标准时间", "HNEG": "格陵兰岛东部标准时间", "HEPM": "圣皮埃尔和密克隆群岛夏令时间", "TMST": "土库曼斯坦夏令时间", "HAST": "夏威夷-阿留申标准时间", "WIB": "印度尼西亚西部时间", "ACST": "澳大利亚中部标准时间", "ARST": "阿根廷夏令时间"}, - } -} - -// Locale returns the current translators string locale -func (zh *zh) Locale() string { - return zh.locale -} - -// PluralsCardinal returns the list of cardinal plural rules associated with 'zh' -func (zh *zh) PluralsCardinal() []locales.PluralRule { - return zh.pluralsCardinal -} - -// PluralsOrdinal returns the list of ordinal plural rules associated with 'zh' -func (zh *zh) PluralsOrdinal() []locales.PluralRule { - return zh.pluralsOrdinal -} - -// PluralsRange returns the list of range plural rules associated with 'zh' -func (zh *zh) PluralsRange() []locales.PluralRule { - return zh.pluralsRange -} - -// CardinalPluralRule returns the cardinal PluralRule given 'num' and digits/precision of 'v' for 'zh' -func (zh *zh) CardinalPluralRule(num float64, v uint64) locales.PluralRule { - return locales.PluralRuleOther -} - -// OrdinalPluralRule returns the ordinal PluralRule given 'num' and digits/precision of 'v' for 'zh' -func (zh *zh) OrdinalPluralRule(num float64, v uint64) locales.PluralRule { - return locales.PluralRuleOther -} - -// RangePluralRule returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for 'zh' -func (zh *zh) RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) locales.PluralRule { - return locales.PluralRuleOther -} - -// MonthAbbreviated returns the locales abbreviated month given the 'month' provided -func (zh *zh) MonthAbbreviated(month time.Month) string { - return zh.monthsAbbreviated[month] -} - -// MonthsAbbreviated returns the locales abbreviated months -func (zh *zh) MonthsAbbreviated() []string { - return zh.monthsAbbreviated[1:] -} - -// MonthNarrow returns the locales narrow month given the 'month' provided -func (zh *zh) MonthNarrow(month time.Month) string { - return zh.monthsNarrow[month] -} - -// MonthsNarrow returns the locales narrow months -func (zh *zh) MonthsNarrow() []string { - return zh.monthsNarrow[1:] -} - -// MonthWide returns the locales wide month given the 'month' provided -func (zh *zh) MonthWide(month time.Month) string { - return zh.monthsWide[month] -} - -// MonthsWide returns the locales wide months -func (zh *zh) MonthsWide() []string { - return zh.monthsWide[1:] -} - -// WeekdayAbbreviated returns the locales abbreviated weekday given the 'weekday' provided -func (zh *zh) WeekdayAbbreviated(weekday time.Weekday) string { - return zh.daysAbbreviated[weekday] -} - -// WeekdaysAbbreviated returns the locales abbreviated weekdays -func (zh *zh) WeekdaysAbbreviated() []string { - return zh.daysAbbreviated -} - -// WeekdayNarrow returns the locales narrow weekday given the 'weekday' provided -func (zh *zh) WeekdayNarrow(weekday time.Weekday) string { - return zh.daysNarrow[weekday] -} - -// WeekdaysNarrow returns the locales narrow weekdays -func (zh *zh) WeekdaysNarrow() []string { - return zh.daysNarrow -} - -// WeekdayShort returns the locales short weekday given the 'weekday' provided -func (zh *zh) WeekdayShort(weekday time.Weekday) string { - return zh.daysShort[weekday] -} - -// WeekdaysShort returns the locales short weekdays -func (zh *zh) WeekdaysShort() []string { - return zh.daysShort -} - -// WeekdayWide returns the locales wide weekday given the 'weekday' provided -func (zh *zh) WeekdayWide(weekday time.Weekday) string { - return zh.daysWide[weekday] -} - -// WeekdaysWide returns the locales wide weekdays -func (zh *zh) WeekdaysWide() []string { - return zh.daysWide -} - -// Decimal returns the decimal point of number -func (zh *zh) Decimal() string { - return zh.decimal -} - -// Group returns the group of number -func (zh *zh) Group() string { - return zh.group -} - -// Group returns the minus sign of number -func (zh *zh) Minus() string { - return zh.minus -} - -// FmtNumber returns 'num' with digits/precision of 'v' for 'zh' and handles both Whole and Real numbers based on 'v' -func (zh *zh) FmtNumber(num float64, v uint64) string { - - s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64) - l := len(s) + 2 + 1*len(s[:len(s)-int(v)-1])/3 - count := 0 - inWhole := v == 0 - b := make([]byte, 0, l) - - for i := len(s) - 1; i >= 0; i-- { - - if s[i] == '.' { - b = append(b, zh.decimal[0]) - inWhole = true - continue - } - - if inWhole { - if count == 3 { - b = append(b, zh.group[0]) - count = 1 - } else { - count++ - } - } - - b = append(b, s[i]) - } - - if num < 0 { - b = append(b, zh.minus[0]) - } - - // reverse - for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { - b[i], b[j] = b[j], b[i] - } - - return string(b) -} - -// FmtPercent returns 'num' with digits/precision of 'v' for 'zh' and handles both Whole and Real numbers based on 'v' -// NOTE: 'num' passed into FmtPercent is assumed to be in percent already -func (zh *zh) FmtPercent(num float64, v uint64) string { - s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64) - l := len(s) + 3 - b := make([]byte, 0, l) - - for i := len(s) - 1; i >= 0; i-- { - - if s[i] == '.' { - b = append(b, zh.decimal[0]) - continue - } - - b = append(b, s[i]) - } - - if num < 0 { - b = append(b, zh.minus[0]) - } - - // reverse - for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { - b[i], b[j] = b[j], b[i] - } - - b = append(b, zh.percent...) - - return string(b) -} - -// FmtCurrency returns the currency representation of 'num' with digits/precision of 'v' for 'zh' -func (zh *zh) FmtCurrency(num float64, v uint64, currency currency.Type) string { - - s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64) - symbol := zh.currencies[currency] - l := len(s) + len(symbol) + 2 + 1*len(s[:len(s)-int(v)-1])/3 - count := 0 - inWhole := v == 0 - b := make([]byte, 0, l) - - for i := len(s) - 1; i >= 0; i-- { - - if s[i] == '.' { - b = append(b, zh.decimal[0]) - inWhole = true - continue - } - - if inWhole { - if count == 3 { - b = append(b, zh.group[0]) - count = 1 - } else { - count++ - } - } - - b = append(b, s[i]) - } - - for j := len(symbol) - 1; j >= 0; j-- { - b = append(b, symbol[j]) - } - - if num < 0 { - b = append(b, zh.minus[0]) - } - - // reverse - for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { - b[i], b[j] = b[j], b[i] - } - - if int(v) < 2 { - - if v == 0 { - b = append(b, zh.decimal...) - } - - for i := 0; i < 2-int(v); i++ { - b = append(b, '0') - } - } - - return string(b) -} - -// FmtAccounting returns the currency representation of 'num' with digits/precision of 'v' for 'zh' -// in accounting notation. -func (zh *zh) FmtAccounting(num float64, v uint64, currency currency.Type) string { - - s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64) - symbol := zh.currencies[currency] - l := len(s) + len(symbol) + 2 + 1*len(s[:len(s)-int(v)-1])/3 - count := 0 - inWhole := v == 0 - b := make([]byte, 0, l) - - for i := len(s) - 1; i >= 0; i-- { - - if s[i] == '.' { - b = append(b, zh.decimal[0]) - inWhole = true - continue - } - - if inWhole { - if count == 3 { - b = append(b, zh.group[0]) - count = 1 - } else { - count++ - } - } - - b = append(b, s[i]) - } - - if num < 0 { - - for j := len(symbol) - 1; j >= 0; j-- { - b = append(b, symbol[j]) - } - - b = append(b, zh.minus[0]) - - } else { - - for j := len(symbol) - 1; j >= 0; j-- { - b = append(b, symbol[j]) - } - - } - - // reverse - for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { - b[i], b[j] = b[j], b[i] - } - - if int(v) < 2 { - - if v == 0 { - b = append(b, zh.decimal...) - } - - for i := 0; i < 2-int(v); i++ { - b = append(b, '0') - } - } - - return string(b) -} - -// FmtDateShort returns the short date representation of 't' for 'zh' -func (zh *zh) FmtDateShort(t time.Time) string { - - b := make([]byte, 0, 32) - - if t.Year() > 0 { - b = strconv.AppendInt(b, int64(t.Year()), 10) - } else { - b = strconv.AppendInt(b, int64(-t.Year()), 10) - } - - b = append(b, []byte{0x2f}...) - b = strconv.AppendInt(b, int64(t.Month()), 10) - b = append(b, []byte{0x2f}...) - b = strconv.AppendInt(b, int64(t.Day()), 10) - - return string(b) -} - -// FmtDateMedium returns the medium date representation of 't' for 'zh' -func (zh *zh) FmtDateMedium(t time.Time) string { - - b := make([]byte, 0, 32) - - if t.Year() > 0 { - b = strconv.AppendInt(b, int64(t.Year()), 10) - } else { - b = strconv.AppendInt(b, int64(-t.Year()), 10) - } - - b = append(b, []byte{0xe5, 0xb9, 0xb4}...) - b = strconv.AppendInt(b, int64(t.Month()), 10) - b = append(b, []byte{0xe6, 0x9c, 0x88}...) - b = strconv.AppendInt(b, int64(t.Day()), 10) - b = append(b, []byte{0xe6, 0x97, 0xa5}...) - - return string(b) -} - -// FmtDateLong returns the long date representation of 't' for 'zh' -func (zh *zh) FmtDateLong(t time.Time) string { - - b := make([]byte, 0, 32) - - if t.Year() > 0 { - b = strconv.AppendInt(b, int64(t.Year()), 10) - } else { - b = strconv.AppendInt(b, int64(-t.Year()), 10) - } - - b = append(b, []byte{0xe5, 0xb9, 0xb4}...) - b = strconv.AppendInt(b, int64(t.Month()), 10) - b = append(b, []byte{0xe6, 0x9c, 0x88}...) - b = strconv.AppendInt(b, int64(t.Day()), 10) - b = append(b, []byte{0xe6, 0x97, 0xa5}...) - - return string(b) -} - -// FmtDateFull returns the full date representation of 't' for 'zh' -func (zh *zh) FmtDateFull(t time.Time) string { - - b := make([]byte, 0, 32) - - if t.Year() > 0 { - b = strconv.AppendInt(b, int64(t.Year()), 10) - } else { - b = strconv.AppendInt(b, int64(-t.Year()), 10) - } - - b = append(b, []byte{0xe5, 0xb9, 0xb4}...) - b = strconv.AppendInt(b, int64(t.Month()), 10) - b = append(b, []byte{0xe6, 0x9c, 0x88}...) - b = strconv.AppendInt(b, int64(t.Day()), 10) - b = append(b, []byte{0xe6, 0x97, 0xa5}...) - b = append(b, zh.daysWide[t.Weekday()]...) - - return string(b) -} - -// FmtTimeShort returns the short time representation of 't' for 'zh' -func (zh *zh) FmtTimeShort(t time.Time) string { - - b := make([]byte, 0, 32) - - if t.Hour() < 12 { - b = append(b, zh.periodsAbbreviated[0]...) - } else { - b = append(b, zh.periodsAbbreviated[1]...) - } - - h := t.Hour() - - if h > 12 { - h -= 12 - } - - b = strconv.AppendInt(b, int64(h), 10) - b = append(b, zh.timeSeparator...) - - if t.Minute() < 10 { - b = append(b, '0') - } - - b = strconv.AppendInt(b, int64(t.Minute()), 10) - - return string(b) -} - -// FmtTimeMedium returns the medium time representation of 't' for 'zh' -func (zh *zh) FmtTimeMedium(t time.Time) string { - - b := make([]byte, 0, 32) - - if t.Hour() < 12 { - b = append(b, zh.periodsAbbreviated[0]...) - } else { - b = append(b, zh.periodsAbbreviated[1]...) - } - - h := t.Hour() - - if h > 12 { - h -= 12 - } - - b = strconv.AppendInt(b, int64(h), 10) - b = append(b, zh.timeSeparator...) - - if t.Minute() < 10 { - b = append(b, '0') - } - - b = strconv.AppendInt(b, int64(t.Minute()), 10) - b = append(b, zh.timeSeparator...) - - if t.Second() < 10 { - b = append(b, '0') - } - - b = strconv.AppendInt(b, int64(t.Second()), 10) - - return string(b) -} - -// FmtTimeLong returns the long time representation of 't' for 'zh' -func (zh *zh) FmtTimeLong(t time.Time) string { - - b := make([]byte, 0, 32) - - tz, _ := t.Zone() - b = append(b, tz...) - - b = append(b, []byte{0x20}...) - - if t.Hour() < 12 { - b = append(b, zh.periodsAbbreviated[0]...) - } else { - b = append(b, zh.periodsAbbreviated[1]...) - } - - h := t.Hour() - - if h > 12 { - h -= 12 - } - - b = strconv.AppendInt(b, int64(h), 10) - b = append(b, zh.timeSeparator...) - - if t.Minute() < 10 { - b = append(b, '0') - } - - b = strconv.AppendInt(b, int64(t.Minute()), 10) - b = append(b, zh.timeSeparator...) - - if t.Second() < 10 { - b = append(b, '0') - } - - b = strconv.AppendInt(b, int64(t.Second()), 10) - - return string(b) -} - -// FmtTimeFull returns the full time representation of 't' for 'zh' -func (zh *zh) FmtTimeFull(t time.Time) string { - - b := make([]byte, 0, 32) - - tz, _ := t.Zone() - - if btz, ok := zh.timezones[tz]; ok { - b = append(b, btz...) - } else { - b = append(b, tz...) - } - - b = append(b, []byte{0x20}...) - - if t.Hour() < 12 { - b = append(b, zh.periodsAbbreviated[0]...) - } else { - b = append(b, zh.periodsAbbreviated[1]...) - } - - h := t.Hour() - - if h > 12 { - h -= 12 - } - - b = strconv.AppendInt(b, int64(h), 10) - b = append(b, zh.timeSeparator...) - - if t.Minute() < 10 { - b = append(b, '0') - } - - b = strconv.AppendInt(b, int64(t.Minute()), 10) - b = append(b, zh.timeSeparator...) - - if t.Second() < 10 { - b = append(b, '0') - } - - b = strconv.AppendInt(b, int64(t.Second()), 10) - - return string(b) -} diff --git a/go-playground/universal-translator/.gitignore b/go-playground/universal-translator/.gitignore deleted file mode 100644 index bc4e07f..0000000 --- a/go-playground/universal-translator/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof -*.coverprofile \ No newline at end of file diff --git a/go-playground/universal-translator/.travis.yml b/go-playground/universal-translator/.travis.yml deleted file mode 100644 index 39b8b92..0000000 --- a/go-playground/universal-translator/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: go -go: - - 1.13.4 - - tip -matrix: - allow_failures: - - go: tip - -notifications: - email: - recipients: dean.karn@gmail.com - on_success: change - on_failure: always - -before_install: - - go install github.com/mattn/goveralls - -# Only clone the most recent commit. -git: - depth: 1 - -script: - - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./... - -after_success: | - [ $TRAVIS_GO_VERSION = 1.13.4 ] && - goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN \ No newline at end of file diff --git a/go-playground/universal-translator/LICENSE b/go-playground/universal-translator/LICENSE deleted file mode 100644 index 8d8aba1..0000000 --- a/go-playground/universal-translator/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Go Playground - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/go-playground/universal-translator/README.md b/go-playground/universal-translator/README.md deleted file mode 100644 index 071f33a..0000000 --- a/go-playground/universal-translator/README.md +++ /dev/null @@ -1,89 +0,0 @@ -## universal-translator -![Project status](https://img.shields.io/badge/version-0.17.0-green.svg) -[![Build Status](https://travis-ci.org/go-playground/universal-translator.svg?branch=master)](https://travis-ci.org/go-playground/universal-translator) -[![Coverage Status](https://coveralls.io/repos/github/go-playground/universal-translator/badge.svg)](https://coveralls.io/github/go-playground/universal-translator) -[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/universal-translator)](https://goreportcard.com/report/github.com/go-playground/universal-translator) -[![GoDoc](https://godoc.org/github.com/go-playground/universal-translator?status.svg)](https://godoc.org/github.com/go-playground/universal-translator) -![License](https://img.shields.io/dub/l/vibe-d.svg) -[![Gitter](https://badges.gitter.im/go-playground/universal-translator.svg)](https://gitter.im/go-playground/universal-translator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - -Universal Translator is an i18n Translator for Go/Golang using CLDR data + pluralization rules - -Why another i18n library? --------------------------- -Because none of the plural rules seem to be correct out there, including the previous implementation of this package, -so I took it upon myself to create [locales](https://github.com/go-playground/locales) for everyone to use; this package -is a thin wrapper around [locales](https://github.com/go-playground/locales) in order to store and translate text for -use in your applications. - -Features --------- -- [x] Rules generated from the [CLDR](http://cldr.unicode.org/index/downloads) data, v30.0.3 -- [x] Contains Cardinal, Ordinal and Range Plural Rules -- [x] Contains Month, Weekday and Timezone translations built in -- [x] Contains Date & Time formatting functions -- [x] Contains Number, Currency, Accounting and Percent formatting functions -- [x] Supports the "Gregorian" calendar only ( my time isn't unlimited, had to draw the line somewhere ) -- [x] Support loading translations from files -- [x] Exporting translations to file(s), mainly for getting them professionally translated -- [ ] Code Generation for translation files -> Go code.. i.e. after it has been professionally translated -- [ ] Tests for all languages, I need help with this, please see [here](https://github.com/go-playground/locales/issues/1) - -Installation ------------ - -Use go get - -```shell -go get github.com/go-playground/universal-translator -``` - -Usage & Documentation -------- - -Please see https://godoc.org/github.com/go-playground/universal-translator for usage docs - -##### Examples: - -- [Basic](https://github.com/go-playground/universal-translator/tree/master/_examples/basic) -- [Full - no files](https://github.com/go-playground/universal-translator/tree/master/_examples/full-no-files) -- [Full - with files](https://github.com/go-playground/universal-translator/tree/master/_examples/full-with-files) - -File formatting --------------- -All types, Plain substitution, Cardinal, Ordinal and Range translations can all be contained withing the same file(s); -they are only separated for easy viewing. - -##### Examples: - -- [Formats](https://github.com/go-playground/universal-translator/tree/master/_examples/file-formats) - -##### Basic Makeup -NOTE: not all fields are needed for all translation types, see [examples](https://github.com/go-playground/universal-translator/tree/master/_examples/file-formats) -```json -{ - "locale": "en", - "key": "days-left", - "trans": "You have {0} day left.", - "type": "Cardinal", - "rule": "One", - "override": false -} -``` -|Field|Description| -|---|---| -|locale|The locale for which the translation is for.| -|key|The translation key that will be used to store and lookup each translation; normally it is a string or integer.| -|trans|The actual translation text.| -|type|The type of translation Cardinal, Ordinal, Range or "" for a plain substitution(not required to be defined if plain used)| -|rule|The plural rule for which the translation is for eg. One, Two, Few, Many or Other.(not required to be defined if plain used)| -|override|If you wish to override an existing translation that has already been registered, set this to 'true'. 99% of the time there is no need to define it.| - -Help With Tests ---------------- -To anyone interesting in helping or contributing, I sure could use some help creating tests for each language. -Please see issue [here](https://github.com/go-playground/locales/issues/1) for details. - -License ------- -Distributed under MIT License, please see license file in code for more details. diff --git a/go-playground/universal-translator/errors.go b/go-playground/universal-translator/errors.go deleted file mode 100644 index af6510e..0000000 --- a/go-playground/universal-translator/errors.go +++ /dev/null @@ -1,148 +0,0 @@ -package ut - -import ( - "errors" - "fmt" - - "git.ningdatech.com/ningda/gin_valid/go-playground/locales" -) - -var ( - // ErrUnknowTranslation indicates the translation could not be found - ErrUnknowTranslation = errors.New("Unknown Translation") -) - -var _ error = new(ErrConflictingTranslation) -var _ error = new(ErrRangeTranslation) -var _ error = new(ErrOrdinalTranslation) -var _ error = new(ErrCardinalTranslation) -var _ error = new(ErrMissingPluralTranslation) -var _ error = new(ErrExistingTranslator) - -// ErrExistingTranslator is the error representing a conflicting translator -type ErrExistingTranslator struct { - locale string -} - -// Error returns ErrExistingTranslator's internal error text -func (e *ErrExistingTranslator) Error() string { - return fmt.Sprintf("error: conflicting translator for locale '%s'", e.locale) -} - -// ErrConflictingTranslation is the error representing a conflicting translation -type ErrConflictingTranslation struct { - locale string - key interface{} - rule locales.PluralRule - text string -} - -// Error returns ErrConflictingTranslation's internal error text -func (e *ErrConflictingTranslation) Error() string { - - if _, ok := e.key.(string); !ok { - return fmt.Sprintf("error: conflicting key '%#v' rule '%s' with text '%s' for locale '%s', value being ignored", e.key, e.rule, e.text, e.locale) - } - - return fmt.Sprintf("error: conflicting key '%s' rule '%s' with text '%s' for locale '%s', value being ignored", e.key, e.rule, e.text, e.locale) -} - -// ErrRangeTranslation is the error representing a range translation error -type ErrRangeTranslation struct { - text string -} - -// Error returns ErrRangeTranslation's internal error text -func (e *ErrRangeTranslation) Error() string { - return e.text -} - -// ErrOrdinalTranslation is the error representing an ordinal translation error -type ErrOrdinalTranslation struct { - text string -} - -// Error returns ErrOrdinalTranslation's internal error text -func (e *ErrOrdinalTranslation) Error() string { - return e.text -} - -// ErrCardinalTranslation is the error representing a cardinal translation error -type ErrCardinalTranslation struct { - text string -} - -// Error returns ErrCardinalTranslation's internal error text -func (e *ErrCardinalTranslation) Error() string { - return e.text -} - -// ErrMissingPluralTranslation is the error signifying a missing translation given -// the locales plural rules. -type ErrMissingPluralTranslation struct { - locale string - key interface{} - rule locales.PluralRule - translationType string -} - -// Error returns ErrMissingPluralTranslation's internal error text -func (e *ErrMissingPluralTranslation) Error() string { - - if _, ok := e.key.(string); !ok { - return fmt.Sprintf("error: missing '%s' plural rule '%s' for translation with key '%#v' and locale '%s'", e.translationType, e.rule, e.key, e.locale) - } - - return fmt.Sprintf("error: missing '%s' plural rule '%s' for translation with key '%s' and locale '%s'", e.translationType, e.rule, e.key, e.locale) -} - -// ErrMissingBracket is the error representing a missing bracket in a translation -// eg. This is a {0 <-- missing ending '}' -type ErrMissingBracket struct { - locale string - key interface{} - text string -} - -// Error returns ErrMissingBracket error message -func (e *ErrMissingBracket) Error() string { - return fmt.Sprintf("error: missing bracket '{}', in translation. locale: '%s' key: '%v' text: '%s'", e.locale, e.key, e.text) -} - -// ErrBadParamSyntax is the error representing a bad parameter definition in a translation -// eg. This is a {must-be-int} -type ErrBadParamSyntax struct { - locale string - param string - key interface{} - text string -} - -// Error returns ErrBadParamSyntax error message -func (e *ErrBadParamSyntax) Error() string { - return fmt.Sprintf("error: bad parameter syntax, missing parameter '%s' in translation. locale: '%s' key: '%v' text: '%s'", e.param, e.locale, e.key, e.text) -} - -// import/export errors - -// ErrMissingLocale is the error representing an expected locale that could -// not be found aka locale not registered with the UniversalTranslator Instance -type ErrMissingLocale struct { - locale string -} - -// Error returns ErrMissingLocale's internal error text -func (e *ErrMissingLocale) Error() string { - return fmt.Sprintf("error: locale '%s' not registered.", e.locale) -} - -// ErrBadPluralDefinition is the error representing an incorrect plural definition -// usually found within translations defined within files during the import process. -type ErrBadPluralDefinition struct { - tl translation -} - -// Error returns ErrBadPluralDefinition's internal error text -func (e *ErrBadPluralDefinition) Error() string { - return fmt.Sprintf("error: bad plural definition '%#v'", e.tl) -} diff --git a/go-playground/universal-translator/import_export.go b/go-playground/universal-translator/import_export.go deleted file mode 100644 index 7cec0d0..0000000 --- a/go-playground/universal-translator/import_export.go +++ /dev/null @@ -1,274 +0,0 @@ -package ut - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path/filepath" - - "io" - - "git.ningdatech.com/ningda/gin_valid/go-playground/locales" -) - -type translation struct { - Locale string `json:"locale"` - Key interface{} `json:"key"` // either string or integer - Translation string `json:"trans"` - PluralType string `json:"type,omitempty"` - PluralRule string `json:"rule,omitempty"` - OverrideExisting bool `json:"override,omitempty"` -} - -const ( - cardinalType = "Cardinal" - ordinalType = "Ordinal" - rangeType = "Range" -) - -// ImportExportFormat is the format of the file import or export -type ImportExportFormat uint8 - -// supported Export Formats -const ( - FormatJSON ImportExportFormat = iota -) - -// Export writes the translations out to a file on disk. -// -// NOTE: this currently only works with string or int translations keys. -func (t *UniversalTranslator) Export(format ImportExportFormat, dirname string) error { - - _, err := os.Stat(dirname) - fmt.Println(dirname, err, os.IsNotExist(err)) - if err != nil { - - if !os.IsNotExist(err) { - return err - } - - if err = os.MkdirAll(dirname, 0744); err != nil { - return err - } - } - - // build up translations - var trans []translation - var b []byte - var ext string - - for _, locale := range t.translators { - - for k, v := range locale.(*translator).translations { - trans = append(trans, translation{ - Locale: locale.Locale(), - Key: k, - Translation: v.text, - }) - } - - for k, pluralTrans := range locale.(*translator).cardinalTanslations { - - for i, plural := range pluralTrans { - - // leave enough for all plural rules - // but not all are set for all languages. - if plural == nil { - continue - } - - trans = append(trans, translation{ - Locale: locale.Locale(), - Key: k.(string), - Translation: plural.text, - PluralType: cardinalType, - PluralRule: locales.PluralRule(i).String(), - }) - } - } - - for k, pluralTrans := range locale.(*translator).ordinalTanslations { - - for i, plural := range pluralTrans { - - // leave enough for all plural rules - // but not all are set for all languages. - if plural == nil { - continue - } - - trans = append(trans, translation{ - Locale: locale.Locale(), - Key: k.(string), - Translation: plural.text, - PluralType: ordinalType, - PluralRule: locales.PluralRule(i).String(), - }) - } - } - - for k, pluralTrans := range locale.(*translator).rangeTanslations { - - for i, plural := range pluralTrans { - - // leave enough for all plural rules - // but not all are set for all languages. - if plural == nil { - continue - } - - trans = append(trans, translation{ - Locale: locale.Locale(), - Key: k.(string), - Translation: plural.text, - PluralType: rangeType, - PluralRule: locales.PluralRule(i).String(), - }) - } - } - - switch format { - case FormatJSON: - b, err = json.MarshalIndent(trans, "", " ") - ext = ".json" - } - - if err != nil { - return err - } - - err = ioutil.WriteFile(filepath.Join(dirname, fmt.Sprintf("%s%s", locale.Locale(), ext)), b, 0644) - if err != nil { - return err - } - - trans = trans[0:0] - } - - return nil -} - -// Import reads the translations out of a file or directory on disk. -// -// NOTE: this currently only works with string or int translations keys. -func (t *UniversalTranslator) Import(format ImportExportFormat, dirnameOrFilename string) error { - - fi, err := os.Stat(dirnameOrFilename) - if err != nil { - return err - } - - processFn := func(filename string) error { - - f, err := os.Open(filename) - if err != nil { - return err - } - defer f.Close() - - return t.ImportByReader(format, f) - } - - if !fi.IsDir() { - return processFn(dirnameOrFilename) - } - - // recursively go through directory - walker := func(path string, info os.FileInfo, err error) error { - - if info.IsDir() { - return nil - } - - switch format { - case FormatJSON: - // skip non JSON files - if filepath.Ext(info.Name()) != ".json" { - return nil - } - } - - return processFn(path) - } - - return filepath.Walk(dirnameOrFilename, walker) -} - -// ImportByReader imports the the translations found within the contents read from the supplied reader. -// -// NOTE: generally used when assets have been embedded into the binary and are already in memory. -func (t *UniversalTranslator) ImportByReader(format ImportExportFormat, reader io.Reader) error { - - b, err := ioutil.ReadAll(reader) - if err != nil { - return err - } - - var trans []translation - - switch format { - case FormatJSON: - err = json.Unmarshal(b, &trans) - } - - if err != nil { - return err - } - - for _, tl := range trans { - - locale, found := t.FindTranslator(tl.Locale) - if !found { - return &ErrMissingLocale{locale: tl.Locale} - } - - pr := stringToPR(tl.PluralRule) - - if pr == locales.PluralRuleUnknown { - - err = locale.Add(tl.Key, tl.Translation, tl.OverrideExisting) - if err != nil { - return err - } - - continue - } - - switch tl.PluralType { - case cardinalType: - err = locale.AddCardinal(tl.Key, tl.Translation, pr, tl.OverrideExisting) - case ordinalType: - err = locale.AddOrdinal(tl.Key, tl.Translation, pr, tl.OverrideExisting) - case rangeType: - err = locale.AddRange(tl.Key, tl.Translation, pr, tl.OverrideExisting) - default: - return &ErrBadPluralDefinition{tl: tl} - } - - if err != nil { - return err - } - } - - return nil -} - -func stringToPR(s string) locales.PluralRule { - - switch s { - case "One": - return locales.PluralRuleOne - case "Two": - return locales.PluralRuleTwo - case "Few": - return locales.PluralRuleFew - case "Many": - return locales.PluralRuleMany - case "Other": - return locales.PluralRuleOther - default: - return locales.PluralRuleUnknown - } - -} diff --git a/go-playground/universal-translator/logo.png b/go-playground/universal-translator/logo.png deleted file mode 100644 index a37aa8c..0000000 Binary files a/go-playground/universal-translator/logo.png and /dev/null differ diff --git a/go-playground/universal-translator/translator.go b/go-playground/universal-translator/translator.go deleted file mode 100644 index 1d89cf9..0000000 --- a/go-playground/universal-translator/translator.go +++ /dev/null @@ -1,420 +0,0 @@ -package ut - -import ( - "fmt" - "strconv" - "strings" - - "git.ningdatech.com/ningda/gin_valid/go-playground/locales" -) - -const ( - paramZero = "{0}" - paramOne = "{1}" - unknownTranslation = "" -) - -// Translator is universal translators -// translator instance which is a thin wrapper -// around locales.Translator instance providing -// some extra functionality -type Translator interface { - locales.Translator - - // adds a normal translation for a particular language/locale - // {#} is the only replacement type accepted and are ad infinitum - // eg. one: '{0} day left' other: '{0} days left' - Add(key interface{}, text string, override bool) error - - // adds a cardinal plural translation for a particular language/locale - // {0} is the only replacement type accepted and only one variable is accepted as - // multiple cannot be used for a plural rule determination, unless it is a range; - // see AddRange below. - // eg. in locale 'en' one: '{0} day left' other: '{0} days left' - AddCardinal(key interface{}, text string, rule locales.PluralRule, override bool) error - - // adds an ordinal plural translation for a particular language/locale - // {0} is the only replacement type accepted and only one variable is accepted as - // multiple cannot be used for a plural rule determination, unless it is a range; - // see AddRange below. - // eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring' - // - 1st, 2nd, 3rd... - AddOrdinal(key interface{}, text string, rule locales.PluralRule, override bool) error - - // adds a range plural translation for a particular language/locale - // {0} and {1} are the only replacement types accepted and only these are accepted. - // eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left' - AddRange(key interface{}, text string, rule locales.PluralRule, override bool) error - - // creates the translation for the locale given the 'key' and params passed in - T(key interface{}, params ...string) (string, error) - - // creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments - // and param passed in - C(key interface{}, num float64, digits uint64, param string) (string, error) - - // creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments - // and param passed in - O(key interface{}, num float64, digits uint64, param string) (string, error) - - // creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and - // 'digit2' arguments and 'param1' and 'param2' passed in - R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) (string, error) - - // VerifyTranslations checks to ensures that no plural rules have been - // missed within the translations. - VerifyTranslations() error -} - -var _ Translator = new(translator) -var _ locales.Translator = new(translator) - -type translator struct { - locales.Translator - translations map[interface{}]*transText - cardinalTanslations map[interface{}][]*transText // array index is mapped to locales.PluralRule index + the locales.PluralRuleUnknown - ordinalTanslations map[interface{}][]*transText - rangeTanslations map[interface{}][]*transText -} - -type transText struct { - text string - indexes []int //记录每个占位符的始末位置,也就是 { 和 } 的位置 -} - -func newTranslator(trans locales.Translator) Translator { - return &translator{ - Translator: trans, - translations: make(map[interface{}]*transText), // translation text broken up by byte index - cardinalTanslations: make(map[interface{}][]*transText), - ordinalTanslations: make(map[interface{}][]*transText), - rangeTanslations: make(map[interface{}][]*transText), - } -} - -// Add adds a normal translation for a particular language/locale -// {#} is the only replacement type accepted and are ad infinitum -// eg. one: '{0} day left' other: '{0} days left' -func (t *translator) Add(key interface{}, text string, override bool) error { - - if _, ok := t.translations[key]; ok && !override { - return &ErrConflictingTranslation{locale: t.Locale(), key: key, text: text} - } - - lb := strings.Count(text, "{") - rb := strings.Count(text, "}") - - if lb != rb { - return &ErrMissingBracket{locale: t.Locale(), key: key, text: text} - } - - trans := &transText{ - text: text, - } - - var idx int - - for i := 0; i < lb; i++ { - s := "{" + strconv.Itoa(i) + "}" - idx = strings.Index(text, s) - if idx == -1 { - return &ErrBadParamSyntax{locale: t.Locale(), param: s, key: key, text: text} - } - - trans.indexes = append(trans.indexes, idx) - trans.indexes = append(trans.indexes, idx+len(s)) - } - - t.translations[key] = trans - - return nil -} - -// AddCardinal adds a cardinal plural translation for a particular language/locale -// {0} is the only replacement type accepted and only one variable is accepted as -// multiple cannot be used for a plural rule determination, unless it is a range; -// see AddRange below. -// eg. in locale 'en' one: '{0} day left' other: '{0} days left' -func (t *translator) AddCardinal(key interface{}, text string, rule locales.PluralRule, override bool) error { - - var verified bool - - // verify plural rule exists for locale - for _, pr := range t.PluralsCardinal() { - if pr == rule { - verified = true - break - } - } - - if !verified { - return &ErrCardinalTranslation{text: fmt.Sprintf("error: cardinal plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)} - } - - tarr, ok := t.cardinalTanslations[key] - if ok { - // verify not adding a conflicting record - if len(tarr) > 0 && tarr[rule] != nil && !override { - return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text} - } - - } else { - tarr = make([]*transText, 7, 7) - t.cardinalTanslations[key] = tarr - } - - trans := &transText{ - text: text, - indexes: make([]int, 2, 2), - } - - tarr[rule] = trans - - idx := strings.Index(text, paramZero) - if idx == -1 { - tarr[rule] = nil - return &ErrCardinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddCardinal'. locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)} - } - - trans.indexes[0] = idx - trans.indexes[1] = idx + len(paramZero) - - return nil -} - -// AddOrdinal adds an ordinal plural translation for a particular language/locale -// {0} is the only replacement type accepted and only one variable is accepted as -// multiple cannot be used for a plural rule determination, unless it is a range; -// see AddRange below. -// eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring' - 1st, 2nd, 3rd... -func (t *translator) AddOrdinal(key interface{}, text string, rule locales.PluralRule, override bool) error { - - var verified bool - - // verify plural rule exists for locale - for _, pr := range t.PluralsOrdinal() { - if pr == rule { - verified = true - break - } - } - - if !verified { - return &ErrOrdinalTranslation{text: fmt.Sprintf("error: ordinal plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)} - } - - tarr, ok := t.ordinalTanslations[key] - if ok { - // verify not adding a conflicting record - if len(tarr) > 0 && tarr[rule] != nil && !override { - return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text} - } - - } else { - tarr = make([]*transText, 7, 7) - t.ordinalTanslations[key] = tarr - } - - trans := &transText{ - text: text, - indexes: make([]int, 2, 2), - } - - tarr[rule] = trans - - idx := strings.Index(text, paramZero) - if idx == -1 { - tarr[rule] = nil - return &ErrOrdinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddOrdinal'. locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)} - } - - trans.indexes[0] = idx - trans.indexes[1] = idx + len(paramZero) - - return nil -} - -// AddRange adds a range plural translation for a particular language/locale -// {0} and {1} are the only replacement types accepted and only these are accepted. -// eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left' -func (t *translator) AddRange(key interface{}, text string, rule locales.PluralRule, override bool) error { - - var verified bool - - // verify plural rule exists for locale - for _, pr := range t.PluralsRange() { - if pr == rule { - verified = true - break - } - } - - if !verified { - return &ErrRangeTranslation{text: fmt.Sprintf("error: range plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)} - } - - tarr, ok := t.rangeTanslations[key] - if ok { - // verify not adding a conflicting record - if len(tarr) > 0 && tarr[rule] != nil && !override { - return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text} - } - - } else { - tarr = make([]*transText, 7, 7) - t.rangeTanslations[key] = tarr - } - - trans := &transText{ - text: text, - indexes: make([]int, 4, 4), - } - - tarr[rule] = trans - - idx := strings.Index(text, paramZero) - if idx == -1 { - tarr[rule] = nil - return &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, are you sure you're adding a Range Translation? locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)} - } - - trans.indexes[0] = idx - trans.indexes[1] = idx + len(paramZero) - - idx = strings.Index(text, paramOne) - if idx == -1 { - tarr[rule] = nil - return &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, a Range Translation requires two parameters. locale: '%s' key: '%v' text: '%s'", paramOne, t.Locale(), key, text)} - } - - trans.indexes[2] = idx - trans.indexes[3] = idx + len(paramOne) - - return nil -} - -// T creates the translation for the locale given the 'key' and params passed in -func (t *translator) T(key interface{}, params ...string) (string, error) { - - trans, ok := t.translations[key] - if !ok { - return unknownTranslation, ErrUnknowTranslation - } - - b := make([]byte, 0, 64) - - var start, end, count int - - for i := 0; i < len(trans.indexes); i++ { - end = trans.indexes[i] - b = append(b, trans.text[start:end]...) - b = append(b, params[count]...) - i++ - start = trans.indexes[i] - count++ - } - - b = append(b, trans.text[start:]...) - - return string(b), nil -} - -// C creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in -func (t *translator) C(key interface{}, num float64, digits uint64, param string) (string, error) { - - tarr, ok := t.cardinalTanslations[key] - if !ok { - return unknownTranslation, ErrUnknowTranslation - } - - rule := t.CardinalPluralRule(num, digits) - - trans := tarr[rule] - - b := make([]byte, 0, 64) - b = append(b, trans.text[:trans.indexes[0]]...) - b = append(b, param...) - b = append(b, trans.text[trans.indexes[1]:]...) - - return string(b), nil -} - -// O creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in -func (t *translator) O(key interface{}, num float64, digits uint64, param string) (string, error) { - - tarr, ok := t.ordinalTanslations[key] - if !ok { - return unknownTranslation, ErrUnknowTranslation - } - - rule := t.OrdinalPluralRule(num, digits) - - trans := tarr[rule] - - b := make([]byte, 0, 64) - b = append(b, trans.text[:trans.indexes[0]]...) - b = append(b, param...) - b = append(b, trans.text[trans.indexes[1]:]...) - - return string(b), nil -} - -// R creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and 'digit2' arguments -// and 'param1' and 'param2' passed in -func (t *translator) R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) (string, error) { - - tarr, ok := t.rangeTanslations[key] - if !ok { - return unknownTranslation, ErrUnknowTranslation - } - - rule := t.RangePluralRule(num1, digits1, num2, digits2) - - trans := tarr[rule] - - b := make([]byte, 0, 64) - b = append(b, trans.text[:trans.indexes[0]]...) - b = append(b, param1...) - b = append(b, trans.text[trans.indexes[1]:trans.indexes[2]]...) - b = append(b, param2...) - b = append(b, trans.text[trans.indexes[3]:]...) - - return string(b), nil -} - -// VerifyTranslations checks to ensures that no plural rules have been -// missed within the translations. -func (t *translator) VerifyTranslations() error { - - for k, v := range t.cardinalTanslations { - - for _, rule := range t.PluralsCardinal() { - - if v[rule] == nil { - return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "plural", rule: rule, key: k} - } - } - } - - for k, v := range t.ordinalTanslations { - - for _, rule := range t.PluralsOrdinal() { - - if v[rule] == nil { - return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "ordinal", rule: rule, key: k} - } - } - } - - for k, v := range t.rangeTanslations { - - for _, rule := range t.PluralsRange() { - - if v[rule] == nil { - return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "range", rule: rule, key: k} - } - } - } - - return nil -} diff --git a/go-playground/universal-translator/universal_translator.go b/go-playground/universal-translator/universal_translator.go deleted file mode 100644 index 6292194..0000000 --- a/go-playground/universal-translator/universal_translator.go +++ /dev/null @@ -1,113 +0,0 @@ -package ut - -import ( - "strings" - - "git.ningdatech.com/ningda/gin_valid/go-playground/locales" -) - -// UniversalTranslator holds all locale & translation data -type UniversalTranslator struct { - translators map[string]Translator - fallback Translator -} - -// New returns a new UniversalTranslator instance set with -// the fallback locale and locales it should support -func New(fallback locales.Translator, supportedLocales ...locales.Translator) *UniversalTranslator { - - t := &UniversalTranslator{ - translators: make(map[string]Translator), - } - - for _, v := range supportedLocales { - - trans := newTranslator(v) - t.translators[strings.ToLower(trans.Locale())] = trans - - if fallback.Locale() == v.Locale() { - t.fallback = trans - } - } - - if t.fallback == nil && fallback != nil { - t.fallback = newTranslator(fallback) - } - - return t -} - -// FindTranslator trys to find a Translator based on an array of locales -// and returns the first one it can find, otherwise returns the -// fallback translator. -func (t *UniversalTranslator) FindTranslator(locales ...string) (trans Translator, found bool) { - - for _, locale := range locales { - - if trans, found = t.translators[strings.ToLower(locale)]; found { - return - } - } - - return t.fallback, false -} - -// GetTranslator returns the specified translator for the given locale, -// or fallback if not found -func (t *UniversalTranslator) GetTranslator(locale string) (trans Translator, found bool) { - - if trans, found = t.translators[strings.ToLower(locale)]; found { - return - } - - return t.fallback, false -} - -// GetFallback returns the fallback locale -func (t *UniversalTranslator) GetFallback() Translator { - return t.fallback -} - -// AddTranslator adds the supplied translator, if it already exists the override param -// will be checked and if false an error will be returned, otherwise the translator will be -// overridden; if the fallback matches the supplied translator it will be overridden as well -// NOTE: this is normally only used when translator is embedded within a library -func (t *UniversalTranslator) AddTranslator(translator locales.Translator, override bool) error { - - lc := strings.ToLower(translator.Locale()) - _, ok := t.translators[lc] - if ok && !override { - return &ErrExistingTranslator{locale: translator.Locale()} - } - - trans := newTranslator(translator) - - if t.fallback.Locale() == translator.Locale() { - - // because it's optional to have a fallback, I don't impose that limitation - // don't know why you wouldn't but... - if !override { - return &ErrExistingTranslator{locale: translator.Locale()} - } - - t.fallback = trans - } - - t.translators[lc] = trans - - return nil -} - -// VerifyTranslations runs through all locales and identifies any issues -// eg. missing plural rules for a locale -func (t *UniversalTranslator) VerifyTranslations() (err error) { - - for _, trans := range t.translators { - err = trans.VerifyTranslations() - if err != nil { - return - } - } - - return -} diff --git a/go-playground/validator/v10/.github/CONTRIBUTING.md b/go-playground/validator/v10/.github/CONTRIBUTING.md deleted file mode 100644 index 6d3811c..0000000 --- a/go-playground/validator/v10/.github/CONTRIBUTING.md +++ /dev/null @@ -1,9 +0,0 @@ -# Contribution Guidelines - -## Quality Standard - -To ensure the continued stability of this package, tests are required to be written or already exist in order for a pull request to be merged. - -## Reporting issues - -Please open an issue or join the gitter chat [![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) for any issues, questions or possible enhancements to the package. diff --git a/go-playground/validator/v10/.github/ISSUE_TEMPLATE.md b/go-playground/validator/v10/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 8afb259..0000000 --- a/go-playground/validator/v10/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,13 +0,0 @@ -### Package version eg. v8, v9: - - - -### Issue, Question or Enhancement: - - - -### Code sample, to showcase or reproduce: - -```go - -``` diff --git a/go-playground/validator/v10/.github/PULL_REQUEST_TEMPLATE.md b/go-playground/validator/v10/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 7bebde3..0000000 --- a/go-playground/validator/v10/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,13 +0,0 @@ -Fixes Or Enhances # . - -**Make sure that you've checked the boxes below before you submit PR:** -- [ ] Tests exist or have been written that cover this particular change. - -Change Details: - -- -- -- - - -@go-playground/admins \ No newline at end of file diff --git a/go-playground/validator/v10/.gitignore b/go-playground/validator/v10/.gitignore deleted file mode 100644 index 6e43fac..0000000 --- a/go-playground/validator/v10/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test -bin - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof -*.test -*.out -*.txt -cover.html -README.html diff --git a/go-playground/validator/v10/.travis.yml b/go-playground/validator/v10/.travis.yml deleted file mode 100644 index 85a7be3..0000000 --- a/go-playground/validator/v10/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: go -go: - - 1.15.2 - - tip -matrix: - allow_failures: - - go: tip - -notifications: - email: - recipients: dean.karn@gmail.com - on_success: change - on_failure: always - -before_install: - - go install github.com/mattn/goveralls - - mkdir -p $GOPATH/src/gopkg.in - - ln -s $GOPATH/src/github.com/$TRAVIS_REPO_SLUG $GOPATH/src/gopkg.in/validator.v9 - -# Only clone the most recent commit. -git: - depth: 1 - -script: - - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./... - -after_success: | - [ $TRAVIS_GO_VERSION = 1.15.2 ] && - goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN diff --git a/go-playground/validator/v10/LICENSE b/go-playground/validator/v10/LICENSE deleted file mode 100644 index 6a2ae9a..0000000 --- a/go-playground/validator/v10/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Dean Karn - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/go-playground/validator/v10/Makefile b/go-playground/validator/v10/Makefile deleted file mode 100644 index 19c91ed..0000000 --- a/go-playground/validator/v10/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -GOCMD=GO111MODULE=on go - -linters-install: - @golangci-lint --version >/dev/null 2>&1 || { \ - echo "installing linting tools..."; \ - curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.21.0; \ - } - -lint: linters-install - $(PWD)/bin/golangci-lint run - -test: - $(GOCMD) test -cover -race ./... - -bench: - $(GOCMD) test -bench=. -benchmem ./... - -.PHONY: test lint linters-install \ No newline at end of file diff --git a/go-playground/validator/v10/README.md b/go-playground/validator/v10/README.md deleted file mode 100644 index 04fbb3c..0000000 --- a/go-playground/validator/v10/README.md +++ /dev/null @@ -1,299 +0,0 @@ -Package validator -================ -[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -![Project status](https://img.shields.io/badge/version-10.4.1-green.svg) -[![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) -[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master) -[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) -[![GoDoc](https://godoc.org/github.com/go-playground/validator?status.svg)](https://pkg.go.dev/github.com/go-playground/validator/v10) -![License](https://img.shields.io/dub/l/vibe-d.svg) - -Package validator implements value validations for structs and individual fields based on tags. - -It has the following **unique** features: - -- Cross Field and Cross Struct validations by using validation tags or custom validators. -- Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated. -- Ability to dive into both map keys and values for validation -- Handles type interface by determining it's underlying type prior to validation. -- Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29) -- Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs -- Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError -- Customizable i18n aware error messages. -- Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/master/_examples/gin-upgrading-overriding) - -Installation ------------- - -Use go get. - - go get github.com/go-playground/validator/v10 - -Then import the validator package into your own code. - - import "github.com/go-playground/validator/v10" - -Error Return Value -------- - -Validation functions return type error - -They return type error to avoid the issue discussed in the following, where err is always != nil: - -* http://stackoverflow.com/a/29138676/3158232 -* https://github.com/go-playground/validator/issues/134 - -Validator only InvalidValidationError for bad validation input, nil or ValidationErrors as type error; so, in your code all you need to do is check if the error returned is not nil, and if it's not check if error is InvalidValidationError ( if necessary, most of the time it isn't ) type cast it to type ValidationErrors like so: - -```go -err := validate.Struct(mystruct) -validationErrors := err.(validator.ValidationErrors) - ``` - -Usage and documentation ------- - -Please see https://godoc.org/github.com/go-playground/validator for detailed usage docs. - -##### Examples: - -- [Simple](https://github.com/go-playground/validator/blob/master/_examples/simple/main.go) -- [Custom Field Types](https://github.com/go-playground/validator/blob/master/_examples/custom/main.go) -- [Struct Level](https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go) -- [Translations & Custom Errors](https://github.com/go-playground/validator/blob/master/_examples/translations/main.go) -- [Gin upgrade and/or override validator](https://github.com/go-playground/validator/tree/v9/_examples/gin-upgrading-overriding) -- [wash - an example application putting it all together](https://github.com/bluesuncorp/wash) - -Baked-in Validations ------- - -### Fields: - -| Tag | Description | -| - | - | -| eqcsfield | Field Equals Another Field (relative)| -| eqfield | Field Equals Another Field | -| fieldcontains | NOT DOCUMENTED IN doc.go | -| fieldexcludes | NOT DOCUMENTED IN doc.go | -| gtcsfield | Field Greater Than Another Relative Field | -| gtecsfield | Field Greater Than or Equal To Another Relative Field | -| gtefield | Field Greater Than or Equal To Another Field | -| gtfield | Field Greater Than Another Field | -| ltcsfield | Less Than Another Relative Field | -| ltecsfield | Less Than or Equal To Another Relative Field | -| ltefield | Less Than or Equal To Another Field | -| ltfield | Less Than Another Field | -| necsfield | Field Does Not Equal Another Field (relative) | -| nefield | Field Does Not Equal Another Field | - -### Network: - -| Tag | Description | -| - | - | -| cidr | Classless Inter-Domain Routing CIDR | -| cidrv4 | Classless Inter-Domain Routing CIDRv4 | -| cidrv6 | Classless Inter-Domain Routing CIDRv6 | -| datauri | Data URL | -| fqdn | Full Qualified Domain Name (FQDN) | -| hostname | Hostname RFC 952 | -| hostname_port | HostPort | -| hostname_rfc1123 | Hostname RFC 1123 | -| ip | Internet Protocol Address IP | -| ip4_addr | Internet Protocol Address IPv4 | -| ip6_addr |Internet Protocol Address IPv6 | -| ip_addr | Internet Protocol Address IP | -| ipv4 | Internet Protocol Address IPv4 | -| ipv6 | Internet Protocol Address IPv6 | -| mac | Media Access Control Address MAC | -| tcp4_addr | Transmission Control Protocol Address TCPv4 | -| tcp6_addr | Transmission Control Protocol Address TCPv6 | -| tcp_addr | Transmission Control Protocol Address TCP | -| udp4_addr | User Datagram Protocol Address UDPv4 | -| udp6_addr | User Datagram Protocol Address UDPv6 | -| udp_addr | User Datagram Protocol Address UDP | -| unix_addr | Unix domain socket end point Address | -| uri | URI String | -| url | URL String | -| url_encoded | URL Encoded | -| urn_rfc2141 | Urn RFC 2141 String | - -### Strings: - -| Tag | Description | -| - | - | -| alpha | Alpha Only | -| alphanum | Alphanumeric | -| alphanumunicode | Alphanumeric Unicode | -| alphaunicode | Alpha Unicode | -| ascii | ASCII | -| contains | Contains | -| containsany | Contains Any | -| containsrune | Contains Rune | -| endswith | Ends With | -| lowercase | Lowercase | -| multibyte | Multi-Byte Characters | -| number | NOT DOCUMENTED IN doc.go | -| numeric | Numeric | -| printascii | Printable ASCII | -| startswith | Starts With | -| uppercase | Uppercase | - -### Format: -| Tag | Description | -| - | - | -| base64 | Base64 String | -| base64url | Base64URL String | -| btc_addr | Bitcoin Address | -| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) | -| datetime | Datetime | -| e164 | e164 formatted phone number | -| email | E-mail String -| eth_addr | Ethereum Address | -| hexadecimal | Hexadecimal String | -| hexcolor | Hexcolor String | -| hsl | HSL String | -| hsla | HSLA String | -| html | HTML Tags | -| html_encoded | HTML Encoded | -| isbn | International Standard Book Number | -| isbn10 | International Standard Book Number 10 | -| isbn13 | International Standard Book Number 13 | -| json | JSON | -| latitude | Latitude | -| longitude | Longitude | -| rgb | RGB String | -| rgba | RGBA String | -| ssn | Social Security Number SSN | -| uuid | Universally Unique Identifier UUID | -| uuid3 | Universally Unique Identifier UUID v3 | -| uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 | -| uuid4 | Universally Unique Identifier UUID v4 | -| uuid4_rfc4122 | Universally Unique Identifier UUID v4 RFC4122 | -| uuid5 | Universally Unique Identifier UUID v5 | -| uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 | -| uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 | - -### Comparisons: -| Tag | Description | -| - | - | -| eq | Equals | -| gt | Greater than| -| gte |Greater than or equal | -| lt | Less Than | -| lte | Less Than or Equal | -| ne | Not Equal | - -### Other: -| Tag | Description | -| - | - | -| dir | Directory | -| endswith | Ends With | -| excludes | Excludes | -| excludesall | Excludes All | -| excludesrune | Excludes Rune | -| file | File path | -| isdefault | Is Default | -| len | Length | -| max | Maximum | -| min | Minimum | -| oneof | One Of | -| required | Required | -| required_if | Required If | -| required_unless | Required Unless | -| required_with | Required With | -| required_with_all | Required With All | -| required_without | Required Without | -| required_without_all | Required Without All | -| excluded_with | Excluded With | -| excluded_with_all | Excluded With All | -| excluded_without | Excluded Without | -| excluded_without_all | Excluded Without All | -| unique | Unique | - -Benchmarks ------- -###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64 -```go -goos: darwin -goarch: amd64 -pkg: github.com/go-playground/validator -BenchmarkFieldSuccess-8 20000000 83.6 ns/op 0 B/op 0 allocs/op -BenchmarkFieldSuccessParallel-8 50000000 26.8 ns/op 0 B/op 0 allocs/op -BenchmarkFieldFailure-8 5000000 291 ns/op 208 B/op 4 allocs/op -BenchmarkFieldFailureParallel-8 20000000 107 ns/op 208 B/op 4 allocs/op -BenchmarkFieldArrayDiveSuccess-8 2000000 623 ns/op 201 B/op 11 allocs/op -BenchmarkFieldArrayDiveSuccessParallel-8 10000000 237 ns/op 201 B/op 11 allocs/op -BenchmarkFieldArrayDiveFailure-8 2000000 859 ns/op 412 B/op 16 allocs/op -BenchmarkFieldArrayDiveFailureParallel-8 5000000 335 ns/op 413 B/op 16 allocs/op -BenchmarkFieldMapDiveSuccess-8 1000000 1292 ns/op 432 B/op 18 allocs/op -BenchmarkFieldMapDiveSuccessParallel-8 3000000 467 ns/op 432 B/op 18 allocs/op -BenchmarkFieldMapDiveFailure-8 1000000 1082 ns/op 512 B/op 16 allocs/op -BenchmarkFieldMapDiveFailureParallel-8 5000000 425 ns/op 512 B/op 16 allocs/op -BenchmarkFieldMapDiveWithKeysSuccess-8 1000000 1539 ns/op 480 B/op 21 allocs/op -BenchmarkFieldMapDiveWithKeysSuccessParallel-8 3000000 613 ns/op 480 B/op 21 allocs/op -BenchmarkFieldMapDiveWithKeysFailure-8 1000000 1413 ns/op 721 B/op 21 allocs/op -BenchmarkFieldMapDiveWithKeysFailureParallel-8 3000000 575 ns/op 721 B/op 21 allocs/op -BenchmarkFieldCustomTypeSuccess-8 10000000 216 ns/op 32 B/op 2 allocs/op -BenchmarkFieldCustomTypeSuccessParallel-8 20000000 82.2 ns/op 32 B/op 2 allocs/op -BenchmarkFieldCustomTypeFailure-8 5000000 274 ns/op 208 B/op 4 allocs/op -BenchmarkFieldCustomTypeFailureParallel-8 20000000 116 ns/op 208 B/op 4 allocs/op -BenchmarkFieldOrTagSuccess-8 2000000 740 ns/op 16 B/op 1 allocs/op -BenchmarkFieldOrTagSuccessParallel-8 3000000 474 ns/op 16 B/op 1 allocs/op -BenchmarkFieldOrTagFailure-8 3000000 471 ns/op 224 B/op 5 allocs/op -BenchmarkFieldOrTagFailureParallel-8 3000000 414 ns/op 224 B/op 5 allocs/op -BenchmarkStructLevelValidationSuccess-8 10000000 213 ns/op 32 B/op 2 allocs/op -BenchmarkStructLevelValidationSuccessParallel-8 20000000 91.8 ns/op 32 B/op 2 allocs/op -BenchmarkStructLevelValidationFailure-8 3000000 473 ns/op 304 B/op 8 allocs/op -BenchmarkStructLevelValidationFailureParallel-8 10000000 234 ns/op 304 B/op 8 allocs/op -BenchmarkStructSimpleCustomTypeSuccess-8 5000000 385 ns/op 32 B/op 2 allocs/op -BenchmarkStructSimpleCustomTypeSuccessParallel-8 10000000 161 ns/op 32 B/op 2 allocs/op -BenchmarkStructSimpleCustomTypeFailure-8 2000000 640 ns/op 424 B/op 9 allocs/op -BenchmarkStructSimpleCustomTypeFailureParallel-8 5000000 318 ns/op 440 B/op 10 allocs/op -BenchmarkStructFilteredSuccess-8 2000000 597 ns/op 288 B/op 9 allocs/op -BenchmarkStructFilteredSuccessParallel-8 10000000 266 ns/op 288 B/op 9 allocs/op -BenchmarkStructFilteredFailure-8 3000000 454 ns/op 256 B/op 7 allocs/op -BenchmarkStructFilteredFailureParallel-8 10000000 214 ns/op 256 B/op 7 allocs/op -BenchmarkStructPartialSuccess-8 3000000 502 ns/op 256 B/op 6 allocs/op -BenchmarkStructPartialSuccessParallel-8 10000000 225 ns/op 256 B/op 6 allocs/op -BenchmarkStructPartialFailure-8 2000000 702 ns/op 480 B/op 11 allocs/op -BenchmarkStructPartialFailureParallel-8 5000000 329 ns/op 480 B/op 11 allocs/op -BenchmarkStructExceptSuccess-8 2000000 793 ns/op 496 B/op 12 allocs/op -BenchmarkStructExceptSuccessParallel-8 10000000 193 ns/op 240 B/op 5 allocs/op -BenchmarkStructExceptFailure-8 2000000 639 ns/op 464 B/op 10 allocs/op -BenchmarkStructExceptFailureParallel-8 5000000 300 ns/op 464 B/op 10 allocs/op -BenchmarkStructSimpleCrossFieldSuccess-8 3000000 417 ns/op 72 B/op 3 allocs/op -BenchmarkStructSimpleCrossFieldSuccessParallel-8 10000000 163 ns/op 72 B/op 3 allocs/op -BenchmarkStructSimpleCrossFieldFailure-8 2000000 645 ns/op 304 B/op 8 allocs/op -BenchmarkStructSimpleCrossFieldFailureParallel-8 5000000 285 ns/op 304 B/op 8 allocs/op -BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3000000 588 ns/op 80 B/op 4 allocs/op -BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 221 ns/op 80 B/op 4 allocs/op -BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 868 ns/op 320 B/op 9 allocs/op -BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 337 ns/op 320 B/op 9 allocs/op -BenchmarkStructSimpleSuccess-8 5000000 260 ns/op 0 B/op 0 allocs/op -BenchmarkStructSimpleSuccessParallel-8 20000000 90.6 ns/op 0 B/op 0 allocs/op -BenchmarkStructSimpleFailure-8 2000000 619 ns/op 424 B/op 9 allocs/op -BenchmarkStructSimpleFailureParallel-8 5000000 296 ns/op 424 B/op 9 allocs/op -BenchmarkStructComplexSuccess-8 1000000 1454 ns/op 128 B/op 8 allocs/op -BenchmarkStructComplexSuccessParallel-8 3000000 579 ns/op 128 B/op 8 allocs/op -BenchmarkStructComplexFailure-8 300000 4140 ns/op 3041 B/op 53 allocs/op -BenchmarkStructComplexFailureParallel-8 1000000 2127 ns/op 3041 B/op 53 allocs/op -BenchmarkOneof-8 10000000 140 ns/op 0 B/op 0 allocs/op -BenchmarkOneofParallel-8 20000000 70.1 ns/op 0 B/op 0 allocs/op -``` - -Complementary Software ----------------------- - -Here is a list of software that complements using this library either pre or post validation. - -* [form](https://github.com/go-playground/form) - Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support. -* [mold](https://github.com/go-playground/mold) - A general library to help modify or set data within data structures and other objects - -How to Contribute ------- - -Make a pull request... - -License ------- -Distributed under MIT License, please see license file within the code for more details. diff --git a/go-playground/validator/v10/baked_in.go b/go-playground/validator/v10/baked_in.go deleted file mode 100644 index 8e41f62..0000000 --- a/go-playground/validator/v10/baked_in.go +++ /dev/null @@ -1,2285 +0,0 @@ -package validator - -import ( - "bytes" - "context" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "net" - "net/url" - "os" - "reflect" - "strconv" - "strings" - "sync" - "time" - "unicode/utf8" - - "golang.org/x/crypto/sha3" - - urn "github.com/leodido/go-urn" -) - -// Func accepts a FieldLevel interface for all validation needs. The return -// value should be true when validation succeeds. -type Func func(fl FieldLevel) bool - -// FuncCtx accepts a context.Context and FieldLevel interface for all -// validation needs. The return value should be true when validation succeeds. -type FuncCtx func(ctx context.Context, fl FieldLevel) bool - -// wrapFunc wraps noramal Func makes it compatible with FuncCtx -func wrapFunc(fn Func) FuncCtx { - if fn == nil { - return nil // be sure not to wrap a bad function. - } - return func(ctx context.Context, fl FieldLevel) bool { - return fn(fl) - } -} - -var ( - restrictedTags = map[string]struct{}{ - diveTag: {}, - keysTag: {}, - endKeysTag: {}, - structOnlyTag: {}, - omitempty: {}, - skipValidationTag: {}, - utf8HexComma: {}, - utf8Pipe: {}, - noStructLevelTag: {}, - requiredTag: {}, - isdefault: {}, - } - - // BakedInAliasValidators is a default mapping of a single validation tag that - // defines a common or complex set of validation(s) to simplify - // adding validation to structs. - bakedInAliases = map[string]string{ - "iscolor": "hexcolor|rgb|rgba|hsl|hsla", - "country_code": "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric", - } - - // BakedInValidators is the default map of ValidationFunc - // you can add, remove or even replace items to suite your needs, - // or even disregard and use your own map if so desired. - bakedInValidators = map[string]Func{ - "required": hasValue, - "required_if": requiredIf, - "required_unless": requiredUnless, - "required_with": requiredWith, - "required_with_all": requiredWithAll, - "required_without": requiredWithout, - "required_without_all": requiredWithoutAll, - "excluded_with": excludedWith, - "excluded_with_all": excludedWithAll, - "excluded_without": excludedWithout, - "excluded_without_all": excludedWithoutAll, - "isdefault": isDefault, - "len": hasLengthOf, - "min": hasMinOf, - "max": hasMaxOf, - "eq": isEq, - "ne": isNe, - "lt": isLt, - "lte": isLte, - "gt": isGt, - "gte": isGte, - "eqfield": isEqField, - "eqcsfield": isEqCrossStructField, - "necsfield": isNeCrossStructField, - "gtcsfield": isGtCrossStructField, - "gtecsfield": isGteCrossStructField, - "ltcsfield": isLtCrossStructField, - "ltecsfield": isLteCrossStructField, - "nefield": isNeField, - "gtefield": isGteField, - "gtfield": isGtField, - "ltefield": isLteField, - "ltfield": isLtField, - "fieldcontains": fieldContains, - "fieldexcludes": fieldExcludes, - "alpha": isAlpha, - "alphanum": isAlphanum, - "alphaunicode": isAlphaUnicode, - "alphanumunicode": isAlphanumUnicode, - "numeric": isNumeric, - "number": isNumber, - "hexadecimal": isHexadecimal, - "hexcolor": isHEXColor, - "rgb": isRGB, - "rgba": isRGBA, - "hsl": isHSL, - "hsla": isHSLA, - "e164": isE164, - "email": isEmail, - "url": isURL, - "uri": isURI, - "urn_rfc2141": isUrnRFC2141, // RFC 2141 - "file": isFile, - "base64": isBase64, - "base64url": isBase64URL, - "contains": contains, - "containsany": containsAny, - "containsrune": containsRune, - "excludes": excludes, - "excludesall": excludesAll, - "excludesrune": excludesRune, - "startswith": startsWith, - "endswith": endsWith, - "startsnotwith": startsNotWith, - "endsnotwith": endsNotWith, - "isbn": isISBN, - "isbn10": isISBN10, - "isbn13": isISBN13, - "eth_addr": isEthereumAddress, - "btc_addr": isBitcoinAddress, - "btc_addr_bech32": isBitcoinBech32Address, - "uuid": isUUID, - "uuid3": isUUID3, - "uuid4": isUUID4, - "uuid5": isUUID5, - "uuid_rfc4122": isUUIDRFC4122, - "uuid3_rfc4122": isUUID3RFC4122, - "uuid4_rfc4122": isUUID4RFC4122, - "uuid5_rfc4122": isUUID5RFC4122, - "ascii": isASCII, - "printascii": isPrintableASCII, - "multibyte": hasMultiByteCharacter, - "datauri": isDataURI, - "latitude": isLatitude, - "longitude": isLongitude, - "ssn": isSSN, - "ipv4": isIPv4, - "ipv6": isIPv6, - "ip": isIP, - "cidrv4": isCIDRv4, - "cidrv6": isCIDRv6, - "cidr": isCIDR, - "tcp4_addr": isTCP4AddrResolvable, - "tcp6_addr": isTCP6AddrResolvable, - "tcp_addr": isTCPAddrResolvable, - "udp4_addr": isUDP4AddrResolvable, - "udp6_addr": isUDP6AddrResolvable, - "udp_addr": isUDPAddrResolvable, - "ip4_addr": isIP4AddrResolvable, - "ip6_addr": isIP6AddrResolvable, - "ip_addr": isIPAddrResolvable, - "unix_addr": isUnixAddrResolvable, - "mac": isMAC, - "hostname": isHostnameRFC952, // RFC 952 - "hostname_rfc1123": isHostnameRFC1123, // RFC 1123 - "fqdn": isFQDN, - "unique": isUnique, - "oneof": isOneOf, - "html": isHTML, - "html_encoded": isHTMLEncoded, - "url_encoded": isURLEncoded, - "dir": isDir, - "json": isJSON, - "hostname_port": isHostnamePort, - "lowercase": isLowercase, - "uppercase": isUppercase, - "datetime": isDatetime, - "timezone": isTimeZone, - "iso3166_1_alpha2": isIso3166Alpha2, - "iso3166_1_alpha3": isIso3166Alpha3, - "iso3166_1_alpha_numeric": isIso3166AlphaNumeric, - } -) - -var oneofValsCache = map[string][]string{} -var oneofValsCacheRWLock = sync.RWMutex{} - -func parseOneOfParam2(s string) []string { - oneofValsCacheRWLock.RLock() - vals, ok := oneofValsCache[s] - oneofValsCacheRWLock.RUnlock() - if !ok { - oneofValsCacheRWLock.Lock() - vals = splitParamsRegex.FindAllString(s, -1) - for i := 0; i < len(vals); i++ { - vals[i] = strings.Replace(vals[i], "'", "", -1) - } - oneofValsCache[s] = vals - oneofValsCacheRWLock.Unlock() - } - return vals -} - -func isURLEncoded(fl FieldLevel) bool { - return uRLEncodedRegex.MatchString(fl.Field().String()) -} - -func isHTMLEncoded(fl FieldLevel) bool { - return hTMLEncodedRegex.MatchString(fl.Field().String()) -} - -func isHTML(fl FieldLevel) bool { - return hTMLRegex.MatchString(fl.Field().String()) -} - -func isOneOf(fl FieldLevel) bool { - vals := parseOneOfParam2(fl.Param()) - - field := fl.Field() - - var v string - switch field.Kind() { - case reflect.String: - v = field.String() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - v = strconv.FormatInt(field.Int(), 10) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - v = strconv.FormatUint(field.Uint(), 10) - default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) - } - for i := 0; i < len(vals); i++ { - if vals[i] == v { - return true - } - } - return false -} - -// isUnique is the validation function for validating if each array|slice|map value is unique -func isUnique(fl FieldLevel) bool { - - field := fl.Field() - param := fl.Param() - v := reflect.ValueOf(struct{}{}) - - switch field.Kind() { - case reflect.Slice, reflect.Array: - elem := field.Type().Elem() - if elem.Kind() == reflect.Ptr { - elem = elem.Elem() - } - - if param == "" { - m := reflect.MakeMap(reflect.MapOf(elem, v.Type())) - - for i := 0; i < field.Len(); i++ { - m.SetMapIndex(reflect.Indirect(field.Index(i)), v) - } - return field.Len() == m.Len() - } - - sf, ok := elem.FieldByName(param) - if !ok { - panic(fmt.Sprintf("Bad field name %s", param)) - } - - sfTyp := sf.Type - if sfTyp.Kind() == reflect.Ptr { - sfTyp = sfTyp.Elem() - } - - m := reflect.MakeMap(reflect.MapOf(sfTyp, v.Type())) - for i := 0; i < field.Len(); i++ { - m.SetMapIndex(reflect.Indirect(reflect.Indirect(field.Index(i)).FieldByName(param)), v) - } - return field.Len() == m.Len() - case reflect.Map: - m := reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type())) - - for _, k := range field.MapKeys() { - m.SetMapIndex(field.MapIndex(k), v) - } - return field.Len() == m.Len() - default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) - } -} - -// IsMAC is the validation function for validating if the field's value is a valid MAC address. -func isMAC(fl FieldLevel) bool { - - _, err := net.ParseMAC(fl.Field().String()) - - return err == nil -} - -// IsCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address. -func isCIDRv4(fl FieldLevel) bool { - - ip, _, err := net.ParseCIDR(fl.Field().String()) - - return err == nil && ip.To4() != nil -} - -// IsCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address. -func isCIDRv6(fl FieldLevel) bool { - - ip, _, err := net.ParseCIDR(fl.Field().String()) - - return err == nil && ip.To4() == nil -} - -// IsCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address. -func isCIDR(fl FieldLevel) bool { - - _, _, err := net.ParseCIDR(fl.Field().String()) - - return err == nil -} - -// IsIPv4 is the validation function for validating if a value is a valid v4 IP address. -func isIPv4(fl FieldLevel) bool { - - ip := net.ParseIP(fl.Field().String()) - - return ip != nil && ip.To4() != nil -} - -// IsIPv6 is the validation function for validating if the field's value is a valid v6 IP address. -func isIPv6(fl FieldLevel) bool { - - ip := net.ParseIP(fl.Field().String()) - - return ip != nil && ip.To4() == nil -} - -// IsIP is the validation function for validating if the field's value is a valid v4 or v6 IP address. -func isIP(fl FieldLevel) bool { - - ip := net.ParseIP(fl.Field().String()) - - return ip != nil -} - -// IsSSN is the validation function for validating if the field's value is a valid SSN. -func isSSN(fl FieldLevel) bool { - - field := fl.Field() - - if field.Len() != 11 { - return false - } - - return sSNRegex.MatchString(field.String()) -} - -// IsLongitude is the validation function for validating if the field's value is a valid longitude coordinate. -func isLongitude(fl FieldLevel) bool { - field := fl.Field() - - var v string - switch field.Kind() { - case reflect.String: - v = field.String() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - v = strconv.FormatInt(field.Int(), 10) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - v = strconv.FormatUint(field.Uint(), 10) - case reflect.Float32: - v = strconv.FormatFloat(field.Float(), 'f', -1, 32) - case reflect.Float64: - v = strconv.FormatFloat(field.Float(), 'f', -1, 64) - default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) - } - - return longitudeRegex.MatchString(v) -} - -// IsLatitude is the validation function for validating if the field's value is a valid latitude coordinate. -func isLatitude(fl FieldLevel) bool { - field := fl.Field() - - var v string - switch field.Kind() { - case reflect.String: - v = field.String() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - v = strconv.FormatInt(field.Int(), 10) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - v = strconv.FormatUint(field.Uint(), 10) - case reflect.Float32: - v = strconv.FormatFloat(field.Float(), 'f', -1, 32) - case reflect.Float64: - v = strconv.FormatFloat(field.Float(), 'f', -1, 64) - default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) - } - - return latitudeRegex.MatchString(v) -} - -// IsDataURI is the validation function for validating if the field's value is a valid data URI. -func isDataURI(fl FieldLevel) bool { - - uri := strings.SplitN(fl.Field().String(), ",", 2) - - if len(uri) != 2 { - return false - } - - if !dataURIRegex.MatchString(uri[0]) { - return false - } - - return base64Regex.MatchString(uri[1]) -} - -// HasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character. -func hasMultiByteCharacter(fl FieldLevel) bool { - - field := fl.Field() - - if field.Len() == 0 { - return true - } - - return multibyteRegex.MatchString(field.String()) -} - -// IsPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character. -func isPrintableASCII(fl FieldLevel) bool { - return printableASCIIRegex.MatchString(fl.Field().String()) -} - -// IsASCII is the validation function for validating if the field's value is a valid ASCII character. -func isASCII(fl FieldLevel) bool { - return aSCIIRegex.MatchString(fl.Field().String()) -} - -// IsUUID5 is the validation function for validating if the field's value is a valid v5 UUID. -func isUUID5(fl FieldLevel) bool { - return uUID5Regex.MatchString(fl.Field().String()) -} - -// IsUUID4 is the validation function for validating if the field's value is a valid v4 UUID. -func isUUID4(fl FieldLevel) bool { - return uUID4Regex.MatchString(fl.Field().String()) -} - -// IsUUID3 is the validation function for validating if the field's value is a valid v3 UUID. -func isUUID3(fl FieldLevel) bool { - return uUID3Regex.MatchString(fl.Field().String()) -} - -// IsUUID is the validation function for validating if the field's value is a valid UUID of any version. -func isUUID(fl FieldLevel) bool { - return uUIDRegex.MatchString(fl.Field().String()) -} - -// IsUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID. -func isUUID5RFC4122(fl FieldLevel) bool { - return uUID5RFC4122Regex.MatchString(fl.Field().String()) -} - -// IsUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID. -func isUUID4RFC4122(fl FieldLevel) bool { - return uUID4RFC4122Regex.MatchString(fl.Field().String()) -} - -// IsUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID. -func isUUID3RFC4122(fl FieldLevel) bool { - return uUID3RFC4122Regex.MatchString(fl.Field().String()) -} - -// IsUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version. -func isUUIDRFC4122(fl FieldLevel) bool { - return uUIDRFC4122Regex.MatchString(fl.Field().String()) -} - -// IsISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN. -func isISBN(fl FieldLevel) bool { - return isISBN10(fl) || isISBN13(fl) -} - -// IsISBN13 is the validation function for validating if the field's value is a valid v13 ISBN. -func isISBN13(fl FieldLevel) bool { - - s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4) - - if !iSBN13Regex.MatchString(s) { - return false - } - - var checksum int32 - var i int32 - - factor := []int32{1, 3} - - for i = 0; i < 12; i++ { - checksum += factor[i%2] * int32(s[i]-'0') - } - - return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0 -} - -// IsISBN10 is the validation function for validating if the field's value is a valid v10 ISBN. -func isISBN10(fl FieldLevel) bool { - - s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3) - - if !iSBN10Regex.MatchString(s) { - return false - } - - var checksum int32 - var i int32 - - for i = 0; i < 9; i++ { - checksum += (i + 1) * int32(s[i]-'0') - } - - if s[9] == 'X' { - checksum += 10 * 10 - } else { - checksum += 10 * int32(s[9]-'0') - } - - return checksum%11 == 0 -} - -// IsEthereumAddress is the validation function for validating if the field's value is a valid Ethereum address. -func isEthereumAddress(fl FieldLevel) bool { - address := fl.Field().String() - - if !ethAddressRegex.MatchString(address) { - return false - } - - if ethaddressRegexUpper.MatchString(address) || ethAddressRegexLower.MatchString(address) { - return true - } - - // Checksum validation. Reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md - address = address[2:] // Skip "0x" prefix. - h := sha3.NewLegacyKeccak256() - // hash.Hash's io.Writer implementation says it never returns an error. https://golang.org/pkg/hash/#Hash - _, _ = h.Write([]byte(strings.ToLower(address))) - hash := hex.EncodeToString(h.Sum(nil)) - - for i := 0; i < len(address); i++ { - if address[i] <= '9' { // Skip 0-9 digits: they don't have upper/lower-case. - continue - } - if hash[i] > '7' && address[i] >= 'a' || hash[i] <= '7' && address[i] <= 'F' { - return false - } - } - - return true -} - -// IsBitcoinAddress is the validation function for validating if the field's value is a valid btc address -func isBitcoinAddress(fl FieldLevel) bool { - address := fl.Field().String() - - if !btcAddressRegex.MatchString(address) { - return false - } - - alphabet := []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") - - decode := [25]byte{} - - for _, n := range []byte(address) { - d := bytes.IndexByte(alphabet, n) - - for i := 24; i >= 0; i-- { - d += 58 * int(decode[i]) - decode[i] = byte(d % 256) - d /= 256 - } - } - - h := sha256.New() - _, _ = h.Write(decode[:21]) - d := h.Sum([]byte{}) - h = sha256.New() - _, _ = h.Write(d) - - validchecksum := [4]byte{} - computedchecksum := [4]byte{} - - copy(computedchecksum[:], h.Sum(d[:0])) - copy(validchecksum[:], decode[21:]) - - return validchecksum == computedchecksum -} - -// IsBitcoinBech32Address is the validation function for validating if the field's value is a valid bech32 btc address -func isBitcoinBech32Address(fl FieldLevel) bool { - address := fl.Field().String() - - if !btcLowerAddressRegexBech32.MatchString(address) && !btcUpperAddressRegexBech32.MatchString(address) { - return false - } - - am := len(address) % 8 - - if am == 0 || am == 3 || am == 5 { - return false - } - - address = strings.ToLower(address) - - alphabet := "qpzry9x8gf2tvdw0s3jn54khce6mua7l" - - hr := []int{3, 3, 0, 2, 3} // the human readable part will always be bc - addr := address[3:] - dp := make([]int, 0, len(addr)) - - for _, c := range addr { - dp = append(dp, strings.IndexRune(alphabet, c)) - } - - ver := dp[0] - - if ver < 0 || ver > 16 { - return false - } - - if ver == 0 { - if len(address) != 42 && len(address) != 62 { - return false - } - } - - values := append(hr, dp...) - - GEN := []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3} - - p := 1 - - for _, v := range values { - b := p >> 25 - p = (p&0x1ffffff)<<5 ^ v - - for i := 0; i < 5; i++ { - if (b>>uint(i))&1 == 1 { - p ^= GEN[i] - } - } - } - - if p != 1 { - return false - } - - b := uint(0) - acc := 0 - mv := (1 << 5) - 1 - var sw []int - - for _, v := range dp[1 : len(dp)-6] { - acc = (acc << 5) | v - b += 5 - for b >= 8 { - b -= 8 - sw = append(sw, (acc>>b)&mv) - } - } - - if len(sw) < 2 || len(sw) > 40 { - return false - } - - return true -} - -// ExcludesRune is the validation function for validating that the field's value does not contain the rune specified within the param. -func excludesRune(fl FieldLevel) bool { - return !containsRune(fl) -} - -// ExcludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param. -func excludesAll(fl FieldLevel) bool { - return !containsAny(fl) -} - -// Excludes is the validation function for validating that the field's value does not contain the text specified within the param. -func excludes(fl FieldLevel) bool { - return !contains(fl) -} - -// ContainsRune is the validation function for validating that the field's value contains the rune specified within the param. -func containsRune(fl FieldLevel) bool { - - r, _ := utf8.DecodeRuneInString(fl.Param()) - - return strings.ContainsRune(fl.Field().String(), r) -} - -// ContainsAny is the validation function for validating that the field's value contains any of the characters specified within the param. -func containsAny(fl FieldLevel) bool { - return strings.ContainsAny(fl.Field().String(), fl.Param()) -} - -// Contains is the validation function for validating that the field's value contains the text specified within the param. -func contains(fl FieldLevel) bool { - return strings.Contains(fl.Field().String(), fl.Param()) -} - -// StartsWith is the validation function for validating that the field's value starts with the text specified within the param. -func startsWith(fl FieldLevel) bool { - return strings.HasPrefix(fl.Field().String(), fl.Param()) -} - -// EndsWith is the validation function for validating that the field's value ends with the text specified within the param. -func endsWith(fl FieldLevel) bool { - return strings.HasSuffix(fl.Field().String(), fl.Param()) -} - -// StartsNotWith is the validation function for validating that the field's value does not start with the text specified within the param. -func startsNotWith(fl FieldLevel) bool { - return !startsWith(fl) -} - -// EndsNotWith is the validation function for validating that the field's value does not end with the text specified within the param. -func endsNotWith(fl FieldLevel) bool { - return !endsWith(fl) -} - -// FieldContains is the validation function for validating if the current field's value contains the field specified by the param's value. -func fieldContains(fl FieldLevel) bool { - field := fl.Field() - - currentField, _, ok := fl.GetStructFieldOK() - - if !ok { - return false - } - - return strings.Contains(field.String(), currentField.String()) -} - -// FieldExcludes is the validation function for validating if the current field's value excludes the field specified by the param's value. -func fieldExcludes(fl FieldLevel) bool { - field := fl.Field() - - currentField, _, ok := fl.GetStructFieldOK() - if !ok { - return true - } - - return !strings.Contains(field.String(), currentField.String()) -} - -// IsNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value. -func isNeField(fl FieldLevel) bool { - - field := fl.Field() - kind := field.Kind() - - currentField, currentKind, ok := fl.GetStructFieldOK() - - if !ok || currentKind != kind { - return true - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() != currentField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() != currentField.Uint() - - case reflect.Float32, reflect.Float64: - return field.Float() != currentField.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) != int64(currentField.Len()) - - case reflect.Struct: - - fieldType := field.Type() - - // Not Same underlying type i.e. struct and time - if fieldType != currentField.Type() { - return true - } - - if fieldType == timeType { - - t := currentField.Interface().(time.Time) - fieldTime := field.Interface().(time.Time) - - return !fieldTime.Equal(t) - } - - } - - // default reflect.String: - return field.String() != currentField.String() -} - -// IsNe is the validation function for validating that the field's value does not equal the provided param value. -func isNe(fl FieldLevel) bool { - return !isEq(fl) -} - -// IsLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value. -func isLteCrossStructField(fl FieldLevel) bool { - - field := fl.Field() - kind := field.Kind() - - topField, topKind, ok := fl.GetStructFieldOK() - if !ok || topKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() <= topField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() <= topField.Uint() - - case reflect.Float32, reflect.Float64: - return field.Float() <= topField.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) <= int64(topField.Len()) - - case reflect.Struct: - - fieldType := field.Type() - - // Not Same underlying type i.e. struct and time - if fieldType != topField.Type() { - return false - } - - if fieldType == timeType { - - fieldTime := field.Interface().(time.Time) - topTime := topField.Interface().(time.Time) - - return fieldTime.Before(topTime) || fieldTime.Equal(topTime) - } - } - - // default reflect.String: - return field.String() <= topField.String() -} - -// IsLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value. -// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. -func isLtCrossStructField(fl FieldLevel) bool { - - field := fl.Field() - kind := field.Kind() - - topField, topKind, ok := fl.GetStructFieldOK() - if !ok || topKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() < topField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() < topField.Uint() - - case reflect.Float32, reflect.Float64: - return field.Float() < topField.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) < int64(topField.Len()) - - case reflect.Struct: - - fieldType := field.Type() - - // Not Same underlying type i.e. struct and time - if fieldType != topField.Type() { - return false - } - - if fieldType == timeType { - - fieldTime := field.Interface().(time.Time) - topTime := topField.Interface().(time.Time) - - return fieldTime.Before(topTime) - } - } - - // default reflect.String: - return field.String() < topField.String() -} - -// IsGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value. -func isGteCrossStructField(fl FieldLevel) bool { - - field := fl.Field() - kind := field.Kind() - - topField, topKind, ok := fl.GetStructFieldOK() - if !ok || topKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() >= topField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() >= topField.Uint() - - case reflect.Float32, reflect.Float64: - return field.Float() >= topField.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) >= int64(topField.Len()) - - case reflect.Struct: - - fieldType := field.Type() - - // Not Same underlying type i.e. struct and time - if fieldType != topField.Type() { - return false - } - - if fieldType == timeType { - - fieldTime := field.Interface().(time.Time) - topTime := topField.Interface().(time.Time) - - return fieldTime.After(topTime) || fieldTime.Equal(topTime) - } - } - - // default reflect.String: - return field.String() >= topField.String() -} - -// IsGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value. -func isGtCrossStructField(fl FieldLevel) bool { - - field := fl.Field() - kind := field.Kind() - - topField, topKind, ok := fl.GetStructFieldOK() - if !ok || topKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() > topField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() > topField.Uint() - - case reflect.Float32, reflect.Float64: - return field.Float() > topField.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) > int64(topField.Len()) - - case reflect.Struct: - - fieldType := field.Type() - - // Not Same underlying type i.e. struct and time - if fieldType != topField.Type() { - return false - } - - if fieldType == timeType { - - fieldTime := field.Interface().(time.Time) - topTime := topField.Interface().(time.Time) - - return fieldTime.After(topTime) - } - } - - // default reflect.String: - return field.String() > topField.String() -} - -// IsNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value. -func isNeCrossStructField(fl FieldLevel) bool { - - field := fl.Field() - kind := field.Kind() - - topField, currentKind, ok := fl.GetStructFieldOK() - if !ok || currentKind != kind { - return true - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return topField.Int() != field.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return topField.Uint() != field.Uint() - - case reflect.Float32, reflect.Float64: - return topField.Float() != field.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(topField.Len()) != int64(field.Len()) - - case reflect.Struct: - - fieldType := field.Type() - - // Not Same underlying type i.e. struct and time - if fieldType != topField.Type() { - return true - } - - if fieldType == timeType { - - t := field.Interface().(time.Time) - fieldTime := topField.Interface().(time.Time) - - return !fieldTime.Equal(t) - } - } - - // default reflect.String: - return topField.String() != field.String() -} - -// IsEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value. -func isEqCrossStructField(fl FieldLevel) bool { - - field := fl.Field() - kind := field.Kind() - - topField, topKind, ok := fl.GetStructFieldOK() - if !ok || topKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return topField.Int() == field.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return topField.Uint() == field.Uint() - - case reflect.Float32, reflect.Float64: - return topField.Float() == field.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(topField.Len()) == int64(field.Len()) - - case reflect.Struct: - - fieldType := field.Type() - - // Not Same underlying type i.e. struct and time - if fieldType != topField.Type() { - return false - } - - if fieldType == timeType { - - t := field.Interface().(time.Time) - fieldTime := topField.Interface().(time.Time) - - return fieldTime.Equal(t) - } - } - - // default reflect.String: - return topField.String() == field.String() -} - -// IsEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value. -func isEqField(fl FieldLevel) bool { - - field := fl.Field() - kind := field.Kind() - - currentField, currentKind, ok := fl.GetStructFieldOK() - if !ok || currentKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() == currentField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() == currentField.Uint() - - case reflect.Float32, reflect.Float64: - return field.Float() == currentField.Float() - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) == int64(currentField.Len()) - - case reflect.Struct: - - fieldType := field.Type() - - // Not Same underlying type i.e. struct and time - if fieldType != currentField.Type() { - return false - } - - if fieldType == timeType { - - t := currentField.Interface().(time.Time) - fieldTime := field.Interface().(time.Time) - - return fieldTime.Equal(t) - } - - } - - // default reflect.String: - return field.String() == currentField.String() -} - -// IsEq is the validation function for validating if the current field's value is equal to the param's value. -func isEq(fl FieldLevel) bool { - - field := fl.Field() - param := fl.Param() - - switch field.Kind() { - - case reflect.String: - return field.String() == param - - case reflect.Slice, reflect.Map, reflect.Array: - p := asInt(param) - - return int64(field.Len()) == p - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asIntFromType(field.Type(), param) - - return field.Int() == p - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p := asUint(param) - - return field.Uint() == p - - case reflect.Float32, reflect.Float64: - p := asFloat(param) - - return field.Float() == p - - case reflect.Bool: - p := asBool(param) - - return field.Bool() == p - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// IsBase64 is the validation function for validating if the current field's value is a valid base 64. -func isBase64(fl FieldLevel) bool { - return base64Regex.MatchString(fl.Field().String()) -} - -// IsBase64URL is the validation function for validating if the current field's value is a valid base64 URL safe string. -func isBase64URL(fl FieldLevel) bool { - return base64URLRegex.MatchString(fl.Field().String()) -} - -// IsURI is the validation function for validating if the current field's value is a valid URI. -func isURI(fl FieldLevel) bool { - - field := fl.Field() - - switch field.Kind() { - - case reflect.String: - - s := field.String() - - // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195 - // emulate browser and strip the '#' suffix prior to validation. see issue-#237 - if i := strings.Index(s, "#"); i > -1 { - s = s[:i] - } - - if len(s) == 0 { - return false - } - - _, err := url.ParseRequestURI(s) - - return err == nil - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// IsURL is the validation function for validating if the current field's value is a valid URL. -func isURL(fl FieldLevel) bool { - - field := fl.Field() - - switch field.Kind() { - - case reflect.String: - - var i int - s := field.String() - - // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195 - // emulate browser and strip the '#' suffix prior to validation. see issue-#237 - if i = strings.Index(s, "#"); i > -1 { - s = s[:i] - } - - if len(s) == 0 { - return false - } - - url, err := url.ParseRequestURI(s) - - if err != nil || url.Scheme == "" { - return false - } - - return true - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141. -func isUrnRFC2141(fl FieldLevel) bool { - field := fl.Field() - - switch field.Kind() { - - case reflect.String: - - str := field.String() - - _, match := urn.Parse([]byte(str)) - - return match - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// IsFile is the validation function for validating if the current field's value is a valid file path. -func isFile(fl FieldLevel) bool { - field := fl.Field() - - switch field.Kind() { - case reflect.String: - fileInfo, err := os.Stat(field.String()) - if err != nil { - return false - } - - return !fileInfo.IsDir() - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// IsE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number. -func isE164(fl FieldLevel) bool { - return e164Regex.MatchString(fl.Field().String()) -} - -// IsEmail is the validation function for validating if the current field's value is a valid email address. -func isEmail(fl FieldLevel) bool { - return emailRegex.MatchString(fl.Field().String()) -} - -// IsHSLA is the validation function for validating if the current field's value is a valid HSLA color. -func isHSLA(fl FieldLevel) bool { - return hslaRegex.MatchString(fl.Field().String()) -} - -// IsHSL is the validation function for validating if the current field's value is a valid HSL color. -func isHSL(fl FieldLevel) bool { - return hslRegex.MatchString(fl.Field().String()) -} - -// IsRGBA is the validation function for validating if the current field's value is a valid RGBA color. -func isRGBA(fl FieldLevel) bool { - return rgbaRegex.MatchString(fl.Field().String()) -} - -// IsRGB is the validation function for validating if the current field's value is a valid RGB color. -func isRGB(fl FieldLevel) bool { - return rgbRegex.MatchString(fl.Field().String()) -} - -// IsHEXColor is the validation function for validating if the current field's value is a valid HEX color. -func isHEXColor(fl FieldLevel) bool { - return hexcolorRegex.MatchString(fl.Field().String()) -} - -// IsHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal. -func isHexadecimal(fl FieldLevel) bool { - return hexadecimalRegex.MatchString(fl.Field().String()) -} - -// IsNumber is the validation function for validating if the current field's value is a valid number. -func isNumber(fl FieldLevel) bool { - switch fl.Field().Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64: - return true - default: - return numberRegex.MatchString(fl.Field().String()) - } -} - -// IsNumeric is the validation function for validating if the current field's value is a valid numeric value. -func isNumeric(fl FieldLevel) bool { - switch fl.Field().Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64: - return true - default: - return numericRegex.MatchString(fl.Field().String()) - } -} - -// IsAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value. -func isAlphanum(fl FieldLevel) bool { - return alphaNumericRegex.MatchString(fl.Field().String()) -} - -// IsAlpha is the validation function for validating if the current field's value is a valid alpha value. -func isAlpha(fl FieldLevel) bool { - return alphaRegex.MatchString(fl.Field().String()) -} - -// IsAlphanumUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value. -func isAlphanumUnicode(fl FieldLevel) bool { - return alphaUnicodeNumericRegex.MatchString(fl.Field().String()) -} - -// IsAlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value. -func isAlphaUnicode(fl FieldLevel) bool { - return alphaUnicodeRegex.MatchString(fl.Field().String()) -} - -// isDefault is the opposite of required aka hasValue -func isDefault(fl FieldLevel) bool { - return !hasValue(fl) -} - -// HasValue is the validation function for validating if the current field's value is not the default static value. -func hasValue(fl FieldLevel) bool { - field := fl.Field() - switch field.Kind() { - case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: - return !field.IsNil() - default: - if fl.(*validate).fldIsPointer && field.Interface() != nil { - return true - } - return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface() - } -} - -// requireCheckField is a func for check field kind -func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue bool) bool { - field := fl.Field() - kind := field.Kind() - var nullable, found bool - if len(param) > 0 { - field, kind, nullable, found = fl.GetStructFieldOKAdvanced2(fl.Parent(), param) - if !found { - return defaultNotFoundValue - } - } - switch kind { - case reflect.Invalid: - return defaultNotFoundValue - case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: - return field.IsNil() - default: - if nullable && field.Interface() != nil { - return false - } - return field.IsValid() && field.Interface() == reflect.Zero(field.Type()).Interface() - } -} - -// requireCheckFieldValue is a func for check field value -func requireCheckFieldValue(fl FieldLevel, param string, value string, defaultNotFoundValue bool) bool { - field, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), param) - if !found { - return defaultNotFoundValue - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return field.Int() == asInt(value) - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return field.Uint() == asUint(value) - - case reflect.Float32, reflect.Float64: - return field.Float() == asFloat(value) - - case reflect.Slice, reflect.Map, reflect.Array: - return int64(field.Len()) == asInt(value) - } - - // default reflect.String: - return field.String() == value -} - -// requiredIf is the validation function -// The field under validation must be present and not empty only if all the other specified fields are equal to the value following with the specified field. -func requiredIf(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - if len(params)%2 != 0 { - panic(fmt.Sprintf("Bad param number for required_if %s", fl.FieldName())) - } - for i := 0; i < len(params); i += 2 { - if !requireCheckFieldValue(fl, params[i], params[i+1], false) { - return true - } - } - return hasValue(fl) -} - -// requiredUnless is the validation function -// The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field. -func requiredUnless(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - if len(params)%2 != 0 { - panic(fmt.Sprintf("Bad param number for required_unless %s", fl.FieldName())) - } - - for i := 0; i < len(params); i += 2 { - if requireCheckFieldValue(fl, params[i], params[i+1], false) { - return true - } - } - return hasValue(fl) -} - -// ExcludedWith is the validation function -// The field under validation must not be present or is empty if any of the other specified fields are present. -func excludedWith(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - for _, param := range params { - if !requireCheckFieldKind(fl, param, true) { - return !hasValue(fl) - } - } - return true -} - -// RequiredWith is the validation function -// The field under validation must be present and not empty only if any of the other specified fields are present. -func requiredWith(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - for _, param := range params { - if !requireCheckFieldKind(fl, param, true) { - return hasValue(fl) - } - } - return true -} - -// ExcludedWithAll is the validation function -// The field under validation must not be present or is empty if all of the other specified fields are present. -func excludedWithAll(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - for _, param := range params { - if requireCheckFieldKind(fl, param, true) { - return true - } - } - return !hasValue(fl) -} - -// RequiredWithAll is the validation function -// The field under validation must be present and not empty only if all of the other specified fields are present. -func requiredWithAll(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - for _, param := range params { - if requireCheckFieldKind(fl, param, true) { - return true - } - } - return hasValue(fl) -} - -// ExcludedWithout is the validation function -// The field under validation must not be present or is empty when any of the other specified fields are not present. -func excludedWithout(fl FieldLevel) bool { - if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { - return !hasValue(fl) - } - return true -} - -// RequiredWithout is the validation function -// The field under validation must be present and not empty only when any of the other specified fields are not present. -func requiredWithout(fl FieldLevel) bool { - if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { - return hasValue(fl) - } - return true -} - -// RequiredWithoutAll is the validation function -// The field under validation must not be present or is empty when all of the other specified fields are not present. -func excludedWithoutAll(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - for _, param := range params { - if !requireCheckFieldKind(fl, param, true) { - return true - } - } - return !hasValue(fl) -} - -// RequiredWithoutAll is the validation function -// The field under validation must be present and not empty only when all of the other specified fields are not present. -func requiredWithoutAll(fl FieldLevel) bool { - params := parseOneOfParam2(fl.Param()) - for _, param := range params { - if !requireCheckFieldKind(fl, param, true) { - return true - } - } - return hasValue(fl) -} - -// IsGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value. -func isGteField(fl FieldLevel) bool { - - field := fl.Field() - kind := field.Kind() - - currentField, currentKind, ok := fl.GetStructFieldOK() - if !ok || currentKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - - return field.Int() >= currentField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - - return field.Uint() >= currentField.Uint() - - case reflect.Float32, reflect.Float64: - - return field.Float() >= currentField.Float() - - case reflect.Struct: - - fieldType := field.Type() - - // Not Same underlying type i.e. struct and time - if fieldType != currentField.Type() { - return false - } - - if fieldType == timeType { - - t := currentField.Interface().(time.Time) - fieldTime := field.Interface().(time.Time) - - return fieldTime.After(t) || fieldTime.Equal(t) - } - } - - // default reflect.String - return len(field.String()) >= len(currentField.String()) -} - -// IsGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value. -func isGtField(fl FieldLevel) bool { - - field := fl.Field() - kind := field.Kind() - - currentField, currentKind, ok := fl.GetStructFieldOK() - if !ok || currentKind != kind { // 首先会 比较找到的 field 和现在的类型作比较 - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - - return field.Int() > currentField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - - return field.Uint() > currentField.Uint() - - case reflect.Float32, reflect.Float64: - - return field.Float() > currentField.Float() - - case reflect.Struct: - - fieldType := field.Type() - - // Not Same underlying type i.e. struct and time - if fieldType != currentField.Type() { - return false - } - - if fieldType == timeType { - - t := currentField.Interface().(time.Time) - fieldTime := field.Interface().(time.Time) - - return fieldTime.After(t) - } - } - - // default reflect.String - return len(field.String()) > len(currentField.String()) -} - -// IsGte is the validation function for validating if the current field's value is greater than or equal to the param's value. -func isGte(fl FieldLevel) bool { - - field := fl.Field() - param := fl.Param() - - switch field.Kind() { - - case reflect.String: - p := asInt(param) - - return int64(utf8.RuneCountInString(field.String())) >= p - - case reflect.Slice, reflect.Map, reflect.Array: - p := asInt(param) - - return int64(field.Len()) >= p - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asIntFromType(field.Type(), param) - - return field.Int() >= p - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p := asUint(param) - - return field.Uint() >= p - - case reflect.Float32, reflect.Float64: - p := asFloat(param) - - return field.Float() >= p - - case reflect.Struct: - - if field.Type() == timeType { - - now := time.Now().UTC() - t := field.Interface().(time.Time) - - return t.After(now) || t.Equal(now) - } - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// IsGt is the validation function for validating if the current field's value is greater than the param's value. -func isGt(fl FieldLevel) bool { - - field := fl.Field() - param := fl.Param() - - switch field.Kind() { - - case reflect.String: - p := asInt(param) - - return int64(utf8.RuneCountInString(field.String())) > p - - case reflect.Slice, reflect.Map, reflect.Array: - p := asInt(param) - - return int64(field.Len()) > p - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asIntFromType(field.Type(), param) - - return field.Int() > p - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p := asUint(param) - - return field.Uint() > p - - case reflect.Float32, reflect.Float64: - p := asFloat(param) - - return field.Float() > p - case reflect.Struct: - - if field.Type() == timeType { - - return field.Interface().(time.Time).After(time.Now().UTC()) - } - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// HasLengthOf is the validation function for validating if the current field's value is equal to the param's value. -func hasLengthOf(fl FieldLevel) bool { - - field := fl.Field() - param := fl.Param() - - switch field.Kind() { - - case reflect.String: - p := asInt(param) - - return int64(utf8.RuneCountInString(field.String())) == p - - case reflect.Slice, reflect.Map, reflect.Array: - p := asInt(param) - - return int64(field.Len()) == p - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asIntFromType(field.Type(), param) - - return field.Int() == p - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p := asUint(param) - - return field.Uint() == p - - case reflect.Float32, reflect.Float64: - p := asFloat(param) - - return field.Float() == p - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// HasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value. -func hasMinOf(fl FieldLevel) bool { - return isGte(fl) -} - -// IsLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value. -func isLteField(fl FieldLevel) bool { - - field := fl.Field() - kind := field.Kind() - - currentField, currentKind, ok := fl.GetStructFieldOK() - if !ok || currentKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - - return field.Int() <= currentField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - - return field.Uint() <= currentField.Uint() - - case reflect.Float32, reflect.Float64: - - return field.Float() <= currentField.Float() - - case reflect.Struct: - - fieldType := field.Type() - - // Not Same underlying type i.e. struct and time - if fieldType != currentField.Type() { - return false - } - - if fieldType == timeType { - - t := currentField.Interface().(time.Time) - fieldTime := field.Interface().(time.Time) - - return fieldTime.Before(t) || fieldTime.Equal(t) - } - } - - // default reflect.String - return len(field.String()) <= len(currentField.String()) -} - -// IsLtField is the validation function for validating if the current field's value is less than the field specified by the param's value. -func isLtField(fl FieldLevel) bool { - - field := fl.Field() - kind := field.Kind() - - currentField, currentKind, ok := fl.GetStructFieldOK() - if !ok || currentKind != kind { - return false - } - - switch kind { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - - return field.Int() < currentField.Int() - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - - return field.Uint() < currentField.Uint() - - case reflect.Float32, reflect.Float64: - - return field.Float() < currentField.Float() - - case reflect.Struct: - - fieldType := field.Type() - - // Not Same underlying type i.e. struct and time - if fieldType != currentField.Type() { - return false - } - - if fieldType == timeType { - - t := currentField.Interface().(time.Time) - fieldTime := field.Interface().(time.Time) - - return fieldTime.Before(t) - } - } - - // default reflect.String - return len(field.String()) < len(currentField.String()) -} - -// IsLte is the validation function for validating if the current field's value is less than or equal to the param's value. -func isLte(fl FieldLevel) bool { - - field := fl.Field() - param := fl.Param() - - switch field.Kind() { - - case reflect.String: - p := asInt(param) - - return int64(utf8.RuneCountInString(field.String())) <= p - - case reflect.Slice, reflect.Map, reflect.Array: - p := asInt(param) - - return int64(field.Len()) <= p - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asIntFromType(field.Type(), param) - - return field.Int() <= p - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p := asUint(param) - - return field.Uint() <= p - - case reflect.Float32, reflect.Float64: - p := asFloat(param) - - return field.Float() <= p - - case reflect.Struct: - - if field.Type() == timeType { - - now := time.Now().UTC() - t := field.Interface().(time.Time) - - return t.Before(now) || t.Equal(now) - } - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// IsLt is the validation function for validating if the current field's value is less than the param's value. -func isLt(fl FieldLevel) bool { - - field := fl.Field() - param := fl.Param() - - switch field.Kind() { - - case reflect.String: - p := asInt(param) - - return int64(utf8.RuneCountInString(field.String())) < p - - case reflect.Slice, reflect.Map, reflect.Array: - p := asInt(param) - - return int64(field.Len()) < p - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p := asIntFromType(field.Type(), param) - - return field.Int() < p - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p := asUint(param) - - return field.Uint() < p - - case reflect.Float32, reflect.Float64: - p := asFloat(param) - - return field.Float() < p - - case reflect.Struct: - - if field.Type() == timeType { - - return field.Interface().(time.Time).Before(time.Now().UTC()) - } - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// HasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value. -func hasMaxOf(fl FieldLevel) bool { - return isLte(fl) -} - -// IsTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address. -func isTCP4AddrResolvable(fl FieldLevel) bool { - - if !isIP4Addr(fl) { - return false - } - - _, err := net.ResolveTCPAddr("tcp4", fl.Field().String()) - return err == nil -} - -// IsTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address. -func isTCP6AddrResolvable(fl FieldLevel) bool { - - if !isIP6Addr(fl) { - return false - } - - _, err := net.ResolveTCPAddr("tcp6", fl.Field().String()) - - return err == nil -} - -// IsTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address. -func isTCPAddrResolvable(fl FieldLevel) bool { - - if !isIP4Addr(fl) && !isIP6Addr(fl) { - return false - } - - _, err := net.ResolveTCPAddr("tcp", fl.Field().String()) - - return err == nil -} - -// IsUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address. -func isUDP4AddrResolvable(fl FieldLevel) bool { - - if !isIP4Addr(fl) { - return false - } - - _, err := net.ResolveUDPAddr("udp4", fl.Field().String()) - - return err == nil -} - -// IsUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address. -func isUDP6AddrResolvable(fl FieldLevel) bool { - - if !isIP6Addr(fl) { - return false - } - - _, err := net.ResolveUDPAddr("udp6", fl.Field().String()) - - return err == nil -} - -// IsUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address. -func isUDPAddrResolvable(fl FieldLevel) bool { - - if !isIP4Addr(fl) && !isIP6Addr(fl) { - return false - } - - _, err := net.ResolveUDPAddr("udp", fl.Field().String()) - - return err == nil -} - -// IsIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address. -func isIP4AddrResolvable(fl FieldLevel) bool { - - if !isIPv4(fl) { - return false - } - - _, err := net.ResolveIPAddr("ip4", fl.Field().String()) - - return err == nil -} - -// IsIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address. -func isIP6AddrResolvable(fl FieldLevel) bool { - - if !isIPv6(fl) { - return false - } - - _, err := net.ResolveIPAddr("ip6", fl.Field().String()) - - return err == nil -} - -// IsIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address. -func isIPAddrResolvable(fl FieldLevel) bool { - - if !isIP(fl) { - return false - } - - _, err := net.ResolveIPAddr("ip", fl.Field().String()) - - return err == nil -} - -// IsUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address. -func isUnixAddrResolvable(fl FieldLevel) bool { - - _, err := net.ResolveUnixAddr("unix", fl.Field().String()) - - return err == nil -} - -func isIP4Addr(fl FieldLevel) bool { - - val := fl.Field().String() - - if idx := strings.LastIndex(val, ":"); idx != -1 { - val = val[0:idx] - } - - ip := net.ParseIP(val) - - return ip != nil && ip.To4() != nil -} - -func isIP6Addr(fl FieldLevel) bool { - - val := fl.Field().String() - - if idx := strings.LastIndex(val, ":"); idx != -1 { - if idx != 0 && val[idx-1:idx] == "]" { - val = val[1 : idx-1] - } - } - - ip := net.ParseIP(val) - - return ip != nil && ip.To4() == nil -} - -func isHostnameRFC952(fl FieldLevel) bool { - return hostnameRegexRFC952.MatchString(fl.Field().String()) -} - -func isHostnameRFC1123(fl FieldLevel) bool { - return hostnameRegexRFC1123.MatchString(fl.Field().String()) -} - -func isFQDN(fl FieldLevel) bool { - val := fl.Field().String() - - if val == "" { - return false - } - - return fqdnRegexRFC1123.MatchString(val) -} - -// IsDir is the validation function for validating if the current field's value is a valid directory. -func isDir(fl FieldLevel) bool { - field := fl.Field() - - if field.Kind() == reflect.String { - fileInfo, err := os.Stat(field.String()) - if err != nil { - return false - } - - return fileInfo.IsDir() - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isJSON is the validation function for validating if the current field's value is a valid json string. -func isJSON(fl FieldLevel) bool { - field := fl.Field() - - if field.Kind() == reflect.String { - val := field.String() - return json.Valid([]byte(val)) - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isHostnamePort validates a : combination for fields typically used for socket address. -func isHostnamePort(fl FieldLevel) bool { - val := fl.Field().String() - host, port, err := net.SplitHostPort(val) - if err != nil { - return false - } - // Port must be a iny <= 65535. - if portNum, err := strconv.ParseInt(port, 10, 32); err != nil || portNum > 65535 || portNum < 1 { - return false - } - - // If host is specified, it should match a DNS name - if host != "" { - return hostnameRegexRFC1123.MatchString(host) - } - return true -} - -// isLowercase is the validation function for validating if the current field's value is a lowercase string. -func isLowercase(fl FieldLevel) bool { - field := fl.Field() - - if field.Kind() == reflect.String { - if field.String() == "" { - return false - } - return field.String() == strings.ToLower(field.String()) - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isUppercase is the validation function for validating if the current field's value is an uppercase string. -func isUppercase(fl FieldLevel) bool { - field := fl.Field() - - if field.Kind() == reflect.String { - if field.String() == "" { - return false - } - return field.String() == strings.ToUpper(field.String()) - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isDatetime is the validation function for validating if the current field's value is a valid datetime string. -func isDatetime(fl FieldLevel) bool { - field := fl.Field() - param := fl.Param() - - if field.Kind() == reflect.String { - _, err := time.Parse(param, field.String()) - - return err == nil - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isTimeZone is the validation function for validating if the current field's value is a valid time zone string. -func isTimeZone(fl FieldLevel) bool { - field := fl.Field() - - if field.Kind() == reflect.String { - // empty value is converted to UTC by time.LoadLocation but disallow it as it is not a valid time zone name - if field.String() == "" { - return false - } - - // Local value is converted to the current system time zone by time.LoadLocation but disallow it as it is not a valid time zone name - if strings.ToLower(field.String()) == "local" { - return false - } - - _, err := time.LoadLocation(field.String()) - return err == nil - } - - panic(fmt.Sprintf("Bad field type %T", field.Interface())) -} - -// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-2 country code. -func isIso3166Alpha2(fl FieldLevel) bool { - val := fl.Field().String() - return iso3166_1_alpha2[val] -} - -// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 country code. -func isIso3166Alpha3(fl FieldLevel) bool { - val := fl.Field().String() - return iso3166_1_alpha3[val] -} - -// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric country code. -func isIso3166AlphaNumeric(fl FieldLevel) bool { - field := fl.Field() - - var code int - switch field.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - code = int(field.Int() % 1000) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - code = int(field.Uint() % 1000) - default: - panic(fmt.Sprintf("Bad field type %T", field.Interface())) - } - return iso3166_1_alpha_numeric[code] -} diff --git a/go-playground/validator/v10/cache.go b/go-playground/validator/v10/cache.go deleted file mode 100644 index df48ce1..0000000 --- a/go-playground/validator/v10/cache.go +++ /dev/null @@ -1,322 +0,0 @@ -package validator - -import ( - "fmt" - "reflect" - "strings" - "sync" - "sync/atomic" -) - -type tagType uint8 - -const ( - typeDefault tagType = iota - typeOmitEmpty - typeIsDefault - typeNoStructLevel - typeStructOnly - typeDive - typeOr - typeKeys - typeEndKeys -) - -const ( - invalidValidation = "Invalid validation tag on field '%s'" - undefinedValidation = "Undefined validation function '%s' on field '%s'" - keysTagNotDefined = "'" + endKeysTag + "' tag encountered without a corresponding '" + keysTag + "' tag" -) - -type structCache struct { - lock sync.Mutex - m atomic.Value // map[reflect.Type]*cStruct -} - -func (sc *structCache) Get(key reflect.Type) (c *cStruct, found bool) { - c, found = sc.m.Load().(map[reflect.Type]*cStruct)[key] //有一个断言的封装 - return -} - -func (sc *structCache) Set(key reflect.Type, value *cStruct) { - m := sc.m.Load().(map[reflect.Type]*cStruct) - nm := make(map[reflect.Type]*cStruct, len(m)+1) - for k, v := range m { - nm[k] = v - } - nm[key] = value - sc.m.Store(nm) -} - -type tagCache struct { - lock sync.Mutex - m atomic.Value // map[string]*cTag -} - -func (tc *tagCache) Get(key string) (c *cTag, found bool) { - c, found = tc.m.Load().(map[string]*cTag)[key] - return -} - -func (tc *tagCache) Set(key string, value *cTag) { - m := tc.m.Load().(map[string]*cTag) - nm := make(map[string]*cTag, len(m)+1) - for k, v := range m { - nm[k] = v - } - nm[key] = value - tc.m.Store(nm) -} - -type cStruct struct { - name string - fields []*cField - fn StructLevelFuncCtx -} - -type cField struct { - idx int - name string // field.name - altName string // 如果没有自定义 tagNameFunc,就是field.name, 如果有,比如可以按 json_tag中的, 报错的时候就会按照这个 报错 - namesEqual bool // field.name 和 altName是否相同 - cTags *cTag //以链表的形式存在 -} - -type cTag struct { - tag string // (gte=10) 实际是 gte,不带参数 - aliasTag string // 应该是别名, 不过在没有别名的时候等同于 tag - actualAliasTag string // 实际名字,而不是在func *Validate.parseFieldTagsRecursive 解析后的 别名 - param string - keys *cTag // only populated when using tag's 'keys' and 'endkeys' for map key validation - next *cTag - fn FuncCtx - typeof tagType - hasTag bool - hasAlias bool - hasParam bool // true if parameter used eg. eq= where the equal sign has been set - isBlockEnd bool // indicates the current tag represents the last validation in the block , 表示当前field的最后一个,比如 `require,gte=10`,那么到gte就是true - runValidationWhenNil bool -} - -func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct { - v.structCache.lock.Lock() - defer v.structCache.lock.Unlock() // leave as defer! because if inner panics, it will never get unlocked otherwise! - - typ := current.Type() - - // could have been multiple trying to access, but once first is done this ensures struct - // isn't parsed again. - cs, ok := v.structCache.Get(typ) - if ok { - return cs - } - - cs = &cStruct{name: sName, fields: make([]*cField, 0), fn: v.structLevelFuncs[typ]} - - numFields := current.NumField() - - var ctag *cTag - var fld reflect.StructField - var tag string - var customName string - - for i := 0; i < numFields; i++ { - - fld = typ.Field(i) - - if !fld.Anonymous && len(fld.PkgPath) > 0 { // 如果不是 嵌套field 且是 未导出字段, (大写的字段 pakPath为空) - continue - } - - tag = fld.Tag.Get(v.tagName) - - if tag == skipValidationTag { - continue - } - - customName = fld.Name - - if v.hasTagNameFunc { // 自定义的获取 名字的func - name := v.tagNameFunc(fld) - if len(name) > 0 { - customName = name - } - } - - // NOTE: cannot use shared tag cache, because tags may be equal, but things like alias may be different - // and so only struct level caching can be used instead of combined with Field tag caching - - if len(tag) > 0 { - ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, "", false) //返回链头 - } else { - // even if field doesn't have validations need cTag for traversing to potential inner/nested - // elements of the field. - ctag = new(cTag) - } - - cs.fields = append(cs.fields, &cField{ - idx: i, - name: fld.Name, - altName: customName, - cTags: ctag, - namesEqual: fld.Name == customName, - }) - } - v.structCache.Set(typ, cs) - return cs -} - -func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) { - var t string - noAlias := len(alias) == 0 - tags := strings.Split(tag, tagSeparator) - - for i := 0; i < len(tags); i++ { - t = tags[i] - if noAlias { - alias = t - } - - // check map for alias and process new tags, otherwise process as usual - if tagsVal, found := v.aliases[t]; found { - if i == 0 { - firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) - } else { - next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) - current.next, current = next, curr - - } - continue - } - - var prevTag tagType - - if i == 0 { - current = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true, typeof: typeDefault} - firstCtag = current - } else { - prevTag = current.typeof // 此刻之前current 还是 上一个的状态 - current.next = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true} - current = current.next - } - - switch t { - case diveTag: - current.typeof = typeDive - continue - - case keysTag: - current.typeof = typeKeys - - if i == 0 || prevTag != typeDive { - panic(fmt.Sprintf("'%s' tag must be immediately preceded by the '%s' tag", keysTag, diveTag)) - } - - current.typeof = typeKeys - - // need to pass along only keys tag - // need to increment i to skip over the keys tags - b := make([]byte, 0, 64) - - i++ - - for ; i < len(tags); i++ { - - b = append(b, tags[i]...) - b = append(b, ',') - - if tags[i] == endKeysTag { - break - } - } - - current.keys, _ = v.parseFieldTagsRecursive(string(b[:len(b)-1]), fieldName, "", false) - continue - - case endKeysTag: - current.typeof = typeEndKeys - - // if there are more in tags then there was no keysTag defined - // and an error should be thrown - if i != len(tags)-1 { - panic(keysTagNotDefined) - } - return - - case omitempty: - current.typeof = typeOmitEmpty - continue - - case structOnlyTag: - current.typeof = typeStructOnly - continue - - case noStructLevelTag: - current.typeof = typeNoStructLevel - continue - - default: - if t == isdefault { - current.typeof = typeIsDefault - } - // if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C" - orVals := strings.Split(t, orSeparator) - - for j := 0; j < len(orVals); j++ { - vals := strings.SplitN(orVals[j], tagKeySeparator, 2) // binding:"gte=10" 的 = - if noAlias { - alias = vals[0] //如果没有别名就 gte , 前面的是 gte=10 - current.aliasTag = alias - } else { - current.actualAliasTag = t // 原始名字 gte=10 - } - - if j > 0 { //这里的current.next 不应该是 .pre 前一个么,不过前一个也不对啊,后面的赋值还是给 current赋值啊 - current.next = &cTag{aliasTag: alias, actualAliasTag: current.actualAliasTag, hasAlias: hasAlias, hasTag: true} - current = current.next - } - current.hasParam = len(vals) > 1 - - current.tag = vals[0] - if len(current.tag) == 0 { - panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName))) - } - - if wrapper, ok := v.validations[current.tag]; ok { - current.fn = wrapper.fn - current.runValidationWhenNil = wrapper.runValidatinOnNil - } else { - panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, current.tag, fieldName))) - } - - if len(orVals) > 1 { - current.typeof = typeOr - } - - if len(vals) > 1 { - current.param = strings.Replace(strings.Replace(vals[1], utf8HexComma, ",", -1), utf8Pipe, "|", -1) - } - } - current.isBlockEnd = true - } - } - return -} - -func (v *Validate) fetchCacheTag(tag string) *cTag { - // find cached tag - ctag, found := v.tagCache.Get(tag) - if !found { - v.tagCache.lock.Lock() - defer v.tagCache.lock.Unlock() - - // could have been multiple trying to access, but once first is done this ensures tag - // isn't parsed again. - ctag, found = v.tagCache.Get(tag) - if !found { - ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false) - v.tagCache.Set(tag, ctag) - } - } - return ctag -} diff --git a/go-playground/validator/v10/country_codes.go b/go-playground/validator/v10/country_codes.go deleted file mode 100644 index ef81ead..0000000 --- a/go-playground/validator/v10/country_codes.go +++ /dev/null @@ -1,162 +0,0 @@ -package validator - -var iso3166_1_alpha2 = map[string]bool{ - // see: https://www.iso.org/iso-3166-country-codes.html - "AF": true, "AX": true, "AL": true, "DZ": true, "AS": true, - "AD": true, "AO": true, "AI": true, "AQ": true, "AG": true, - "AR": true, "AM": true, "AW": true, "AU": true, "AT": true, - "AZ": true, "BS": true, "BH": true, "BD": true, "BB": true, - "BY": true, "BE": true, "BZ": true, "BJ": true, "BM": true, - "BT": true, "BO": true, "BQ": true, "BA": true, "BW": true, - "BV": true, "BR": true, "IO": true, "BN": true, "BG": true, - "BF": true, "BI": true, "KH": true, "CM": true, "CA": true, - "CV": true, "KY": true, "CF": true, "TD": true, "CL": true, - "CN": true, "CX": true, "CC": true, "CO": true, "KM": true, - "CG": true, "CD": true, "CK": true, "CR": true, "CI": true, - "HR": true, "CU": true, "CW": true, "CY": true, "CZ": true, - "DK": true, "DJ": true, "DM": true, "DO": true, "EC": true, - "EG": true, "SV": true, "GQ": true, "ER": true, "EE": true, - "ET": true, "FK": true, "FO": true, "FJ": true, "FI": true, - "FR": true, "GF": true, "PF": true, "TF": true, "GA": true, - "GM": true, "GE": true, "DE": true, "GH": true, "GI": true, - "GR": true, "GL": true, "GD": true, "GP": true, "GU": true, - "GT": true, "GG": true, "GN": true, "GW": true, "GY": true, - "HT": true, "HM": true, "VA": true, "HN": true, "HK": true, - "HU": true, "IS": true, "IN": true, "ID": true, "IR": true, - "IQ": true, "IE": true, "IM": true, "IL": true, "IT": true, - "JM": true, "JP": true, "JE": true, "JO": true, "KZ": true, - "KE": true, "KI": true, "KP": true, "KR": true, "KW": true, - "KG": true, "LA": true, "LV": true, "LB": true, "LS": true, - "LR": true, "LY": true, "LI": true, "LT": true, "LU": true, - "MO": true, "MK": true, "MG": true, "MW": true, "MY": true, - "MV": true, "ML": true, "MT": true, "MH": true, "MQ": true, - "MR": true, "MU": true, "YT": true, "MX": true, "FM": true, - "MD": true, "MC": true, "MN": true, "ME": true, "MS": true, - "MA": true, "MZ": true, "MM": true, "NA": true, "NR": true, - "NP": true, "NL": true, "NC": true, "NZ": true, "NI": true, - "NE": true, "NG": true, "NU": true, "NF": true, "MP": true, - "NO": true, "OM": true, "PK": true, "PW": true, "PS": true, - "PA": true, "PG": true, "PY": true, "PE": true, "PH": true, - "PN": true, "PL": true, "PT": true, "PR": true, "QA": true, - "RE": true, "RO": true, "RU": true, "RW": true, "BL": true, - "SH": true, "KN": true, "LC": true, "MF": true, "PM": true, - "VC": true, "WS": true, "SM": true, "ST": true, "SA": true, - "SN": true, "RS": true, "SC": true, "SL": true, "SG": true, - "SX": true, "SK": true, "SI": true, "SB": true, "SO": true, - "ZA": true, "GS": true, "SS": true, "ES": true, "LK": true, - "SD": true, "SR": true, "SJ": true, "SZ": true, "SE": true, - "CH": true, "SY": true, "TW": true, "TJ": true, "TZ": true, - "TH": true, "TL": true, "TG": true, "TK": true, "TO": true, - "TT": true, "TN": true, "TR": true, "TM": true, "TC": true, - "TV": true, "UG": true, "UA": true, "AE": true, "GB": true, - "US": true, "UM": true, "UY": true, "UZ": true, "VU": true, - "VE": true, "VN": true, "VG": true, "VI": true, "WF": true, - "EH": true, "YE": true, "ZM": true, "ZW": true, -} - -var iso3166_1_alpha3 = map[string]bool{ - // see: https://www.iso.org/iso-3166-country-codes.html - "AFG": true, "ALB": true, "DZA": true, "ASM": true, "AND": true, - "AGO": true, "AIA": true, "ATA": true, "ATG": true, "ARG": true, - "ARM": true, "ABW": true, "AUS": true, "AUT": true, "AZE": true, - "BHS": true, "BHR": true, "BGD": true, "BRB": true, "BLR": true, - "BEL": true, "BLZ": true, "BEN": true, "BMU": true, "BTN": true, - "BOL": true, "BES": true, "BIH": true, "BWA": true, "BVT": true, - "BRA": true, "IOT": true, "BRN": true, "BGR": true, "BFA": true, - "BDI": true, "CPV": true, "KHM": true, "CMR": true, "CAN": true, - "CYM": true, "CAF": true, "TCD": true, "CHL": true, "CHN": true, - "CXR": true, "CCK": true, "COL": true, "COM": true, "COD": true, - "COG": true, "COK": true, "CRI": true, "HRV": true, "CUB": true, - "CUW": true, "CYP": true, "CZE": true, "CIV": true, "DNK": true, - "DJI": true, "DMA": true, "DOM": true, "ECU": true, "EGY": true, - "SLV": true, "GNQ": true, "ERI": true, "EST": true, "SWZ": true, - "ETH": true, "FLK": true, "FRO": true, "FJI": true, "FIN": true, - "FRA": true, "GUF": true, "PYF": true, "ATF": true, "GAB": true, - "GMB": true, "GEO": true, "DEU": true, "GHA": true, "GIB": true, - "GRC": true, "GRL": true, "GRD": true, "GLP": true, "GUM": true, - "GTM": true, "GGY": true, "GIN": true, "GNB": true, "GUY": true, - "HTI": true, "HMD": true, "VAT": true, "HND": true, "HKG": true, - "HUN": true, "ISL": true, "IND": true, "IDN": true, "IRN": true, - "IRQ": true, "IRL": true, "IMN": true, "ISR": true, "ITA": true, - "JAM": true, "JPN": true, "JEY": true, "JOR": true, "KAZ": true, - "KEN": true, "KIR": true, "PRK": true, "KOR": true, "KWT": true, - "KGZ": true, "LAO": true, "LVA": true, "LBN": true, "LSO": true, - "LBR": true, "LBY": true, "LIE": true, "LTU": true, "LUX": true, - "MAC": true, "MDG": true, "MWI": true, "MYS": true, "MDV": true, - "MLI": true, "MLT": true, "MHL": true, "MTQ": true, "MRT": true, - "MUS": true, "MYT": true, "MEX": true, "FSM": true, "MDA": true, - "MCO": true, "MNG": true, "MNE": true, "MSR": true, "MAR": true, - "MOZ": true, "MMR": true, "NAM": true, "NRU": true, "NPL": true, - "NLD": true, "NCL": true, "NZL": true, "NIC": true, "NER": true, - "NGA": true, "NIU": true, "NFK": true, "MKD": true, "MNP": true, - "NOR": true, "OMN": true, "PAK": true, "PLW": true, "PSE": true, - "PAN": true, "PNG": true, "PRY": true, "PER": true, "PHL": true, - "PCN": true, "POL": true, "PRT": true, "PRI": true, "QAT": true, - "ROU": true, "RUS": true, "RWA": true, "REU": true, "BLM": true, - "SHN": true, "KNA": true, "LCA": true, "MAF": true, "SPM": true, - "VCT": true, "WSM": true, "SMR": true, "STP": true, "SAU": true, - "SEN": true, "SRB": true, "SYC": true, "SLE": true, "SGP": true, - "SXM": true, "SVK": true, "SVN": true, "SLB": true, "SOM": true, - "ZAF": true, "SGS": true, "SSD": true, "ESP": true, "LKA": true, - "SDN": true, "SUR": true, "SJM": true, "SWE": true, "CHE": true, - "SYR": true, "TWN": true, "TJK": true, "TZA": true, "THA": true, - "TLS": true, "TGO": true, "TKL": true, "TON": true, "TTO": true, - "TUN": true, "TUR": true, "TKM": true, "TCA": true, "TUV": true, - "UGA": true, "UKR": true, "ARE": true, "GBR": true, "UMI": true, - "USA": true, "URY": true, "UZB": true, "VUT": true, "VEN": true, - "VNM": true, "VGB": true, "VIR": true, "WLF": true, "ESH": true, - "YEM": true, "ZMB": true, "ZWE": true, "ALA": true, -} -var iso3166_1_alpha_numeric = map[int]bool{ - // see: https://www.iso.org/iso-3166-country-codes.html - 4: true, 8: true, 12: true, 16: true, 20: true, - 24: true, 660: true, 10: true, 28: true, 32: true, - 51: true, 533: true, 36: true, 40: true, 31: true, - 44: true, 48: true, 50: true, 52: true, 112: true, - 56: true, 84: true, 204: true, 60: true, 64: true, - 68: true, 535: true, 70: true, 72: true, 74: true, - 76: true, 86: true, 96: true, 100: true, 854: true, - 108: true, 132: true, 116: true, 120: true, 124: true, - 136: true, 140: true, 148: true, 152: true, 156: true, - 162: true, 166: true, 170: true, 174: true, 180: true, - 178: true, 184: true, 188: true, 191: true, 192: true, - 531: true, 196: true, 203: true, 384: true, 208: true, - 262: true, 212: true, 214: true, 218: true, 818: true, - 222: true, 226: true, 232: true, 233: true, 748: true, - 231: true, 238: true, 234: true, 242: true, 246: true, - 250: true, 254: true, 258: true, 260: true, 266: true, - 270: true, 268: true, 276: true, 288: true, 292: true, - 300: true, 304: true, 308: true, 312: true, 316: true, - 320: true, 831: true, 324: true, 624: true, 328: true, - 332: true, 334: true, 336: true, 340: true, 344: true, - 348: true, 352: true, 356: true, 360: true, 364: true, - 368: true, 372: true, 833: true, 376: true, 380: true, - 388: true, 392: true, 832: true, 400: true, 398: true, - 404: true, 296: true, 408: true, 410: true, 414: true, - 417: true, 418: true, 428: true, 422: true, 426: true, - 430: true, 434: true, 438: true, 440: true, 442: true, - 446: true, 450: true, 454: true, 458: true, 462: true, - 466: true, 470: true, 584: true, 474: true, 478: true, - 480: true, 175: true, 484: true, 583: true, 498: true, - 492: true, 496: true, 499: true, 500: true, 504: true, - 508: true, 104: true, 516: true, 520: true, 524: true, - 528: true, 540: true, 554: true, 558: true, 562: true, - 566: true, 570: true, 574: true, 807: true, 580: true, - 578: true, 512: true, 586: true, 585: true, 275: true, - 591: true, 598: true, 600: true, 604: true, 608: true, - 612: true, 616: true, 620: true, 630: true, 634: true, - 642: true, 643: true, 646: true, 638: true, 652: true, - 654: true, 659: true, 662: true, 663: true, 666: true, - 670: true, 882: true, 674: true, 678: true, 682: true, - 686: true, 688: true, 690: true, 694: true, 702: true, - 534: true, 703: true, 705: true, 90: true, 706: true, - 710: true, 239: true, 728: true, 724: true, 144: true, - 729: true, 740: true, 744: true, 752: true, 756: true, - 760: true, 158: true, 762: true, 834: true, 764: true, - 626: true, 768: true, 772: true, 776: true, 780: true, - 788: true, 792: true, 795: true, 796: true, 798: true, - 800: true, 804: true, 784: true, 826: true, 581: true, - 840: true, 858: true, 860: true, 548: true, 862: true, - 704: true, 92: true, 850: true, 876: true, 732: true, - 887: true, 894: true, 716: true, 248: true, -} diff --git a/go-playground/validator/v10/doc.go b/go-playground/validator/v10/doc.go deleted file mode 100644 index 34f22ad..0000000 --- a/go-playground/validator/v10/doc.go +++ /dev/null @@ -1,1308 +0,0 @@ -/* -Package validator implements value validations for structs and individual fields -based on tags. - -It can also handle Cross-Field and Cross-Struct validation for nested structs -and has the ability to dive into arrays and maps of any type. - -see more examples https://github.com/go-playground/validator/tree/master/_examples - -Validation Functions Return Type error - -Doing things this way is actually the way the standard library does, see the -file.Open method here: - - https://golang.org/pkg/os/#Open. - -The authors return type "error" to avoid the issue discussed in the following, -where err is always != nil: - - http://stackoverflow.com/a/29138676/3158232 - https://github.com/go-playground/validator/issues/134 - -Validator only InvalidValidationError for bad validation input, nil or -ValidationErrors as type error; so, in your code all you need to do is check -if the error returned is not nil, and if it's not check if error is -InvalidValidationError ( if necessary, most of the time it isn't ) type cast -it to type ValidationErrors like so err.(validator.ValidationErrors). - -Custom Validation Functions - -Custom Validation functions can be added. Example: - - // Structure - func customFunc(fl validator.FieldLevel) bool { - - if fl.Field().String() == "invalid" { - return false - } - - return true - } - - validate.RegisterValidation("custom tag name", customFunc) - // NOTES: using the same tag name as an existing function - // will overwrite the existing one - -Cross-Field Validation - -Cross-Field Validation can be done via the following tags: - - eqfield - - nefield - - gtfield - - gtefield - - ltfield - - ltefield - - eqcsfield - - necsfield - - gtcsfield - - gtecsfield - - ltcsfield - - ltecsfield - -If, however, some custom cross-field validation is required, it can be done -using a custom validation. - -Why not just have cross-fields validation tags (i.e. only eqcsfield and not -eqfield)? - -The reason is efficiency. If you want to check a field within the same struct -"eqfield" only has to find the field on the same struct (1 level). But, if we -used "eqcsfield" it could be multiple levels down. Example: - - type Inner struct { - StartDate time.Time - } - - type Outer struct { - InnerStructField *Inner - CreatedAt time.Time `validate:"ltecsfield=InnerStructField.StartDate"` - } - - now := time.Now() - - inner := &Inner{ - StartDate: now, - } - - outer := &Outer{ - InnerStructField: inner, - CreatedAt: now, - } - - errs := validate.Struct(outer) - - // NOTE: when calling validate.Struct(val) topStruct will be the top level struct passed - // into the function - // when calling validate.VarWithValue(val, field, tag) val will be - // whatever you pass, struct, field... - // when calling validate.Field(field, tag) val will be nil - -Multiple Validators - -Multiple validators on a field will process in the order defined. Example: - - type Test struct { - Field `validate:"max=10,min=1"` - } - - // max will be checked then min - -Bad Validator definitions are not handled by the library. Example: - - type Test struct { - Field `validate:"min=10,max=0"` - } - - // this definition of min max will never succeed - -Using Validator Tags - -Baked In Cross-Field validation only compares fields on the same struct. -If Cross-Field + Cross-Struct validation is needed you should implement your -own custom validator. - -Comma (",") is the default separator of validation tags. If you wish to -have a comma included within the parameter (i.e. excludesall=,) you will need to -use the UTF-8 hex representation 0x2C, which is replaced in the code as a comma, -so the above will become excludesall=0x2C. - - type Test struct { - Field `validate:"excludesall=,"` // BAD! Do not include a comma. - Field `validate:"excludesall=0x2C"` // GOOD! Use the UTF-8 hex representation. - } - -Pipe ("|") is the 'or' validation tags deparator. If you wish to -have a pipe included within the parameter i.e. excludesall=| you will need to -use the UTF-8 hex representation 0x7C, which is replaced in the code as a pipe, -so the above will become excludesall=0x7C - - type Test struct { - Field `validate:"excludesall=|"` // BAD! Do not include a a pipe! - Field `validate:"excludesall=0x7C"` // GOOD! Use the UTF-8 hex representation. - } - - -Baked In Validators and Tags - -Here is a list of the current built in validators: - - -Skip Field - -Tells the validation to skip this struct field; this is particularly -handy in ignoring embedded structs from being validated. (Usage: -) - Usage: - - - -Or Operator - -This is the 'or' operator allowing multiple validators to be used and -accepted. (Usage: rgb|rgba) <-- this would allow either rgb or rgba -colors to be accepted. This can also be combined with 'and' for example -( Usage: omitempty,rgb|rgba) - - Usage: | - -StructOnly - -When a field that is a nested struct is encountered, and contains this flag -any validation on the nested struct will be run, but none of the nested -struct fields will be validated. This is useful if inside of your program -you know the struct will be valid, but need to verify it has been assigned. -NOTE: only "required" and "omitempty" can be used on a struct itself. - - Usage: structonly - -NoStructLevel - -Same as structonly tag except that any struct level validations will not run. - - Usage: nostructlevel - -Omit Empty - -Allows conditional validation, for example if a field is not set with -a value (Determined by the "required" validator) then other validation -such as min or max won't run, but if a value is set validation will run. - - Usage: omitempty - -Dive - -This tells the validator to dive into a slice, array or map and validate that -level of the slice, array or map with the validation tags that follow. -Multidimensional nesting is also supported, each level you wish to dive will -require another dive tag. dive has some sub-tags, 'keys' & 'endkeys', please see -the Keys & EndKeys section just below. - - Usage: dive - -Example #1 - - [][]string with validation tag "gt=0,dive,len=1,dive,required" - // gt=0 will be applied to [] - // len=1 will be applied to []string - // required will be applied to string - -Example #2 - - [][]string with validation tag "gt=0,dive,dive,required" - // gt=0 will be applied to [] - // []string will be spared validation - // required will be applied to string - -Keys & EndKeys - -These are to be used together directly after the dive tag and tells the validator -that anything between 'keys' and 'endkeys' applies to the keys of a map and not the -values; think of it like the 'dive' tag, but for map keys instead of values. -Multidimensional nesting is also supported, each level you wish to validate will -require another 'keys' and 'endkeys' tag. These tags are only valid for maps. - - Usage: dive,keys,othertagvalidation(s),endkeys,valuevalidationtags - -Example #1 - - map[string]string with validation tag "gt=0,dive,keys,eg=1|eq=2,endkeys,required" - // gt=0 will be applied to the map itself - // eg=1|eq=2 will be applied to the map keys - // required will be applied to map values - -Example #2 - - map[[2]string]string with validation tag "gt=0,dive,keys,dive,eq=1|eq=2,endkeys,required" - // gt=0 will be applied to the map itself - // eg=1|eq=2 will be applied to each array element in the the map keys - // required will be applied to map values - -Required - -This validates that the value is not the data types default zero value. -For numbers ensures value is not zero. For strings ensures value is -not "". For slices, maps, pointers, interfaces, channels and functions -ensures the value is not nil. - - Usage: required - -Required If - -The field under validation must be present and not empty only if all -the other specified fields are equal to the value following the specified -field. For strings ensures value is not "". For slices, maps, pointers, -interfaces, channels and functions ensures the value is not nil. - - Usage: required_if - -Examples: - - // require the field if the Field1 is equal to the parameter given: - Usage: required_if=Field1 foobar - - // require the field if the Field1 and Field2 is equal to the value respectively: - Usage: required_if=Field1 foo Field2 bar - -Required Unless - -The field under validation must be present and not empty unless all -the other specified fields are equal to the value following the specified -field. For strings ensures value is not "". For slices, maps, pointers, -interfaces, channels and functions ensures the value is not nil. - - Usage: required_unless - -Examples: - - // require the field unless the Field1 is equal to the parameter given: - Usage: required_unless=Field1 foobar - - // require the field unless the Field1 and Field2 is equal to the value respectively: - Usage: required_unless=Field1 foo Field2 bar - -Required With - -The field under validation must be present and not empty only if any -of the other specified fields are present. For strings ensures value is -not "". For slices, maps, pointers, interfaces, channels and functions -ensures the value is not nil. - - Usage: required_with - -Examples: - - // require the field if the Field1 is present: - Usage: required_with=Field1 - - // require the field if the Field1 or Field2 is present: - Usage: required_with=Field1 Field2 - -Required With All - -The field under validation must be present and not empty only if all -of the other specified fields are present. For strings ensures value is -not "". For slices, maps, pointers, interfaces, channels and functions -ensures the value is not nil. - - Usage: required_with_all - -Example: - - // require the field if the Field1 and Field2 is present: - Usage: required_with_all=Field1 Field2 - -Required Without - -The field under validation must be present and not empty only when any -of the other specified fields are not present. For strings ensures value is -not "". For slices, maps, pointers, interfaces, channels and functions -ensures the value is not nil. - - Usage: required_without - -Examples: - - // require the field if the Field1 is not present: - Usage: required_without=Field1 - - // require the field if the Field1 or Field2 is not present: - Usage: required_without=Field1 Field2 - -Required Without All - -The field under validation must be present and not empty only when all -of the other specified fields are not present. For strings ensures value is -not "". For slices, maps, pointers, interfaces, channels and functions -ensures the value is not nil. - - Usage: required_without_all - -Example: - - // require the field if the Field1 and Field2 is not present: - Usage: required_without_all=Field1 Field2 - -Is Default - -This validates that the value is the default value and is almost the -opposite of required. - - Usage: isdefault - -Length - -For numbers, length will ensure that the value is -equal to the parameter given. For strings, it checks that -the string length is exactly that number of characters. For slices, -arrays, and maps, validates the number of items. - -Example #1 - - Usage: len=10 - -Example #2 (time.Duration) - -For time.Duration, len will ensure that the value is equal to the duration given -in the parameter. - - Usage: len=1h30m - -Maximum - -For numbers, max will ensure that the value is -less than or equal to the parameter given. For strings, it checks -that the string length is at most that number of characters. For -slices, arrays, and maps, validates the number of items. - -Example #1 - - Usage: max=10 - -Example #2 (time.Duration) - -For time.Duration, max will ensure that the value is less than or equal to the -duration given in the parameter. - - Usage: max=1h30m - -Minimum - -For numbers, min will ensure that the value is -greater or equal to the parameter given. For strings, it checks that -the string length is at least that number of characters. For slices, -arrays, and maps, validates the number of items. - -Example #1 - - Usage: min=10 - -Example #2 (time.Duration) - -For time.Duration, min will ensure that the value is greater than or equal to -the duration given in the parameter. - - Usage: min=1h30m - -Equals - -For strings & numbers, eq will ensure that the value is -equal to the parameter given. For slices, arrays, and maps, -validates the number of items. - -Example #1 - - Usage: eq=10 - -Example #2 (time.Duration) - -For time.Duration, eq will ensure that the value is equal to the duration given -in the parameter. - - Usage: eq=1h30m - -Not Equal - -For strings & numbers, ne will ensure that the value is not -equal to the parameter given. For slices, arrays, and maps, -validates the number of items. - -Example #1 - - Usage: ne=10 - -Example #2 (time.Duration) - -For time.Duration, ne will ensure that the value is not equal to the duration -given in the parameter. - - Usage: ne=1h30m - -One Of - -For strings, ints, and uints, oneof will ensure that the value -is one of the values in the parameter. The parameter should be -a list of values separated by whitespace. Values may be -strings or numbers. To match strings with spaces in them, include -the target string between single quotes. - - Usage: oneof=red green - oneof='red green' 'blue yellow' - oneof=5 7 9 - -Greater Than - -For numbers, this will ensure that the value is greater than the -parameter given. For strings, it checks that the string length -is greater than that number of characters. For slices, arrays -and maps it validates the number of items. - -Example #1 - - Usage: gt=10 - -Example #2 (time.Time) - -For time.Time ensures the time value is greater than time.Now.UTC(). - - Usage: gt - -Example #3 (time.Duration) - -For time.Duration, gt will ensure that the value is greater than the duration -given in the parameter. - - Usage: gt=1h30m - -Greater Than or Equal - -Same as 'min' above. Kept both to make terminology with 'len' easier. - -Example #1 - - Usage: gte=10 - -Example #2 (time.Time) - -For time.Time ensures the time value is greater than or equal to time.Now.UTC(). - - Usage: gte - -Example #3 (time.Duration) - -For time.Duration, gte will ensure that the value is greater than or equal to -the duration given in the parameter. - - Usage: gte=1h30m - -Less Than - -For numbers, this will ensure that the value is less than the parameter given. -For strings, it checks that the string length is less than that number of -characters. For slices, arrays, and maps it validates the number of items. - -Example #1 - - Usage: lt=10 - -Example #2 (time.Time) - -For time.Time ensures the time value is less than time.Now.UTC(). - - Usage: lt - -Example #3 (time.Duration) - -For time.Duration, lt will ensure that the value is less than the duration given -in the parameter. - - Usage: lt=1h30m - -Less Than or Equal - -Same as 'max' above. Kept both to make terminology with 'len' easier. - -Example #1 - - Usage: lte=10 - -Example #2 (time.Time) - -For time.Time ensures the time value is less than or equal to time.Now.UTC(). - - Usage: lte - -Example #3 (time.Duration) - -For time.Duration, lte will ensure that the value is less than or equal to the -duration given in the parameter. - - Usage: lte=1h30m - -Field Equals Another Field - -This will validate the field value against another fields value either within -a struct or passed in field. - -Example #1: - - // Validation on Password field using: - Usage: eqfield=ConfirmPassword - -Example #2: - - // Validating by field: - validate.VarWithValue(password, confirmpassword, "eqfield") - -Field Equals Another Field (relative) - -This does the same as eqfield except that it validates the field provided relative -to the top level struct. - - Usage: eqcsfield=InnerStructField.Field) - -Field Does Not Equal Another Field - -This will validate the field value against another fields value either within -a struct or passed in field. - -Examples: - - // Confirm two colors are not the same: - // - // Validation on Color field: - Usage: nefield=Color2 - - // Validating by field: - validate.VarWithValue(color1, color2, "nefield") - -Field Does Not Equal Another Field (relative) - -This does the same as nefield except that it validates the field provided -relative to the top level struct. - - Usage: necsfield=InnerStructField.Field - -Field Greater Than Another Field - -Only valid for Numbers, time.Duration and time.Time types, this will validate -the field value against another fields value either within a struct or passed in -field. usage examples are for validation of a Start and End date: - -Example #1: - - // Validation on End field using: - validate.Struct Usage(gtfield=Start) - -Example #2: - - // Validating by field: - validate.VarWithValue(start, end, "gtfield") - -Field Greater Than Another Relative Field - -This does the same as gtfield except that it validates the field provided -relative to the top level struct. - - Usage: gtcsfield=InnerStructField.Field - -Field Greater Than or Equal To Another Field - -Only valid for Numbers, time.Duration and time.Time types, this will validate -the field value against another fields value either within a struct or passed in -field. usage examples are for validation of a Start and End date: - -Example #1: - - // Validation on End field using: - validate.Struct Usage(gtefield=Start) - -Example #2: - - // Validating by field: - validate.VarWithValue(start, end, "gtefield") - -Field Greater Than or Equal To Another Relative Field - -This does the same as gtefield except that it validates the field provided relative -to the top level struct. - - Usage: gtecsfield=InnerStructField.Field - -Less Than Another Field - -Only valid for Numbers, time.Duration and time.Time types, this will validate -the field value against another fields value either within a struct or passed in -field. usage examples are for validation of a Start and End date: - -Example #1: - - // Validation on End field using: - validate.Struct Usage(ltfield=Start) - -Example #2: - - // Validating by field: - validate.VarWithValue(start, end, "ltfield") - -Less Than Another Relative Field - -This does the same as ltfield except that it validates the field provided relative -to the top level struct. - - Usage: ltcsfield=InnerStructField.Field - -Less Than or Equal To Another Field - -Only valid for Numbers, time.Duration and time.Time types, this will validate -the field value against another fields value either within a struct or passed in -field. usage examples are for validation of a Start and End date: - -Example #1: - - // Validation on End field using: - validate.Struct Usage(ltefield=Start) - -Example #2: - - // Validating by field: - validate.VarWithValue(start, end, "ltefield") - -Less Than or Equal To Another Relative Field - -This does the same as ltefield except that it validates the field provided relative -to the top level struct. - - Usage: ltecsfield=InnerStructField.Field - -Field Contains Another Field - -This does the same as contains except for struct fields. It should only be used -with string types. See the behavior of reflect.Value.String() for behavior on -other types. - - Usage: containsfield=InnerStructField.Field - -Field Excludes Another Field - -This does the same as excludes except for struct fields. It should only be used -with string types. See the behavior of reflect.Value.String() for behavior on -other types. - - Usage: excludesfield=InnerStructField.Field - -Unique - -For arrays & slices, unique will ensure that there are no duplicates. -For maps, unique will ensure that there are no duplicate values. -For slices of struct, unique will ensure that there are no duplicate values -in a field of the struct specified via a parameter. - - // For arrays, slices, and maps: - Usage: unique - - // For slices of struct: - Usage: unique=field - -Alpha Only - -This validates that a string value contains ASCII alpha characters only - - Usage: alpha - -Alphanumeric - -This validates that a string value contains ASCII alphanumeric characters only - - Usage: alphanum - -Alpha Unicode - -This validates that a string value contains unicode alpha characters only - - Usage: alphaunicode - -Alphanumeric Unicode - -This validates that a string value contains unicode alphanumeric characters only - - Usage: alphanumunicode - -Number - -This validates that a string value contains number values only. -For integers or float it returns true. - - Usage: number - -Numeric - -This validates that a string value contains a basic numeric value. -basic excludes exponents etc... -for integers or float it returns true. - - Usage: numeric - -Hexadecimal String - -This validates that a string value contains a valid hexadecimal. - - Usage: hexadecimal - -Hexcolor String - -This validates that a string value contains a valid hex color including -hashtag (#) - - Usage: hexcolor - -Lowercase String - -This validates that a string value contains only lowercase characters. An empty string is not a valid lowercase string. - - Usage: lowercase - -Uppercase String - -This validates that a string value contains only uppercase characters. An empty string is not a valid uppercase string. - - Usage: uppercase - -RGB String - -This validates that a string value contains a valid rgb color - - Usage: rgb - -RGBA String - -This validates that a string value contains a valid rgba color - - Usage: rgba - -HSL String - -This validates that a string value contains a valid hsl color - - Usage: hsl - -HSLA String - -This validates that a string value contains a valid hsla color - - Usage: hsla - -E.164 Phone Number String - -This validates that a string value contains a valid E.164 Phone number -https://en.wikipedia.org/wiki/E.164 (ex. +1123456789) - - Usage: e164 - -E-mail String - -This validates that a string value contains a valid email -This may not conform to all possibilities of any rfc standard, but neither -does any email provider accept all possibilities. - - Usage: email - -JSON String - -This validates that a string value is valid JSON - - Usage: json - -File path - -This validates that a string value contains a valid file path and that -the file exists on the machine. -This is done using os.Stat, which is a platform independent function. - - Usage: file - -URL String - -This validates that a string value contains a valid url -This will accept any url the golang request uri accepts but must contain -a schema for example http:// or rtmp:// - - Usage: url - -URI String - -This validates that a string value contains a valid uri -This will accept any uri the golang request uri accepts - - Usage: uri - -Urn RFC 2141 String - -This validataes that a string value contains a valid URN -according to the RFC 2141 spec. - - Usage: urn_rfc2141 - -Base64 String - -This validates that a string value contains a valid base64 value. -Although an empty string is valid base64 this will report an empty string -as an error, if you wish to accept an empty string as valid you can use -this with the omitempty tag. - - Usage: base64 - -Base64URL String - -This validates that a string value contains a valid base64 URL safe value -according the the RFC4648 spec. -Although an empty string is a valid base64 URL safe value, this will report -an empty string as an error, if you wish to accept an empty string as valid -you can use this with the omitempty tag. - - Usage: base64url - -Bitcoin Address - -This validates that a string value contains a valid bitcoin address. -The format of the string is checked to ensure it matches one of the three formats -P2PKH, P2SH and performs checksum validation. - - Usage: btc_addr - -Bitcoin Bech32 Address (segwit) - -This validates that a string value contains a valid bitcoin Bech32 address as defined -by bip-0173 (https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) -Special thanks to Pieter Wuille for providng reference implementations. - - Usage: btc_addr_bech32 - -Ethereum Address - -This validates that a string value contains a valid ethereum address. -The format of the string is checked to ensure it matches the standard Ethereum address format. - - Usage: eth_addr - -Contains - -This validates that a string value contains the substring value. - - Usage: contains=@ - -Contains Any - -This validates that a string value contains any Unicode code points -in the substring value. - - Usage: containsany=!@#? - -Contains Rune - -This validates that a string value contains the supplied rune value. - - Usage: containsrune=@ - -Excludes - -This validates that a string value does not contain the substring value. - - Usage: excludes=@ - -Excludes All - -This validates that a string value does not contain any Unicode code -points in the substring value. - - Usage: excludesall=!@#? - -Excludes Rune - -This validates that a string value does not contain the supplied rune value. - - Usage: excludesrune=@ - -Starts With - -This validates that a string value starts with the supplied string value - - Usage: startswith=hello - -Ends With - -This validates that a string value ends with the supplied string value - - Usage: endswith=goodbye - -Does Not Start With - -This validates that a string value does not start with the supplied string value - - Usage: startsnotwith=hello - -Does Not End With - -This validates that a string value does not end with the supplied string value - - Usage: endsnotwith=goodbye - -International Standard Book Number - -This validates that a string value contains a valid isbn10 or isbn13 value. - - Usage: isbn - -International Standard Book Number 10 - -This validates that a string value contains a valid isbn10 value. - - Usage: isbn10 - -International Standard Book Number 13 - -This validates that a string value contains a valid isbn13 value. - - Usage: isbn13 - -Universally Unique Identifier UUID - -This validates that a string value contains a valid UUID. Uppercase UUID values will not pass - use `uuid_rfc4122` instead. - - Usage: uuid - -Universally Unique Identifier UUID v3 - -This validates that a string value contains a valid version 3 UUID. Uppercase UUID values will not pass - use `uuid3_rfc4122` instead. - - Usage: uuid3 - -Universally Unique Identifier UUID v4 - -This validates that a string value contains a valid version 4 UUID. Uppercase UUID values will not pass - use `uuid4_rfc4122` instead. - - Usage: uuid4 - -Universally Unique Identifier UUID v5 - -This validates that a string value contains a valid version 5 UUID. Uppercase UUID values will not pass - use `uuid5_rfc4122` instead. - - Usage: uuid5 - -ASCII - -This validates that a string value contains only ASCII characters. -NOTE: if the string is blank, this validates as true. - - Usage: ascii - -Printable ASCII - -This validates that a string value contains only printable ASCII characters. -NOTE: if the string is blank, this validates as true. - - Usage: printascii - -Multi-Byte Characters - -This validates that a string value contains one or more multibyte characters. -NOTE: if the string is blank, this validates as true. - - Usage: multibyte - -Data URL - -This validates that a string value contains a valid DataURI. -NOTE: this will also validate that the data portion is valid base64 - - Usage: datauri - -Latitude - -This validates that a string value contains a valid latitude. - - Usage: latitude - -Longitude - -This validates that a string value contains a valid longitude. - - Usage: longitude - -Social Security Number SSN - -This validates that a string value contains a valid U.S. Social Security Number. - - Usage: ssn - -Internet Protocol Address IP - -This validates that a string value contains a valid IP Address. - - Usage: ip - -Internet Protocol Address IPv4 - -This validates that a string value contains a valid v4 IP Address. - - Usage: ipv4 - -Internet Protocol Address IPv6 - -This validates that a string value contains a valid v6 IP Address. - - Usage: ipv6 - -Classless Inter-Domain Routing CIDR - -This validates that a string value contains a valid CIDR Address. - - Usage: cidr - -Classless Inter-Domain Routing CIDRv4 - -This validates that a string value contains a valid v4 CIDR Address. - - Usage: cidrv4 - -Classless Inter-Domain Routing CIDRv6 - -This validates that a string value contains a valid v6 CIDR Address. - - Usage: cidrv6 - -Transmission Control Protocol Address TCP - -This validates that a string value contains a valid resolvable TCP Address. - - Usage: tcp_addr - -Transmission Control Protocol Address TCPv4 - -This validates that a string value contains a valid resolvable v4 TCP Address. - - Usage: tcp4_addr - -Transmission Control Protocol Address TCPv6 - -This validates that a string value contains a valid resolvable v6 TCP Address. - - Usage: tcp6_addr - -User Datagram Protocol Address UDP - -This validates that a string value contains a valid resolvable UDP Address. - - Usage: udp_addr - -User Datagram Protocol Address UDPv4 - -This validates that a string value contains a valid resolvable v4 UDP Address. - - Usage: udp4_addr - -User Datagram Protocol Address UDPv6 - -This validates that a string value contains a valid resolvable v6 UDP Address. - - Usage: udp6_addr - -Internet Protocol Address IP - -This validates that a string value contains a valid resolvable IP Address. - - Usage: ip_addr - -Internet Protocol Address IPv4 - -This validates that a string value contains a valid resolvable v4 IP Address. - - Usage: ip4_addr - -Internet Protocol Address IPv6 - -This validates that a string value contains a valid resolvable v6 IP Address. - - Usage: ip6_addr - -Unix domain socket end point Address - -This validates that a string value contains a valid Unix Address. - - Usage: unix_addr - -Media Access Control Address MAC - -This validates that a string value contains a valid MAC Address. - - Usage: mac - -Note: See Go's ParseMAC for accepted formats and types: - - http://golang.org/src/net/mac.go?s=866:918#L29 - -Hostname RFC 952 - -This validates that a string value is a valid Hostname according to RFC 952 https://tools.ietf.org/html/rfc952 - - Usage: hostname - -Hostname RFC 1123 - -This validates that a string value is a valid Hostname according to RFC 1123 https://tools.ietf.org/html/rfc1123 - - Usage: hostname_rfc1123 or if you want to continue to use 'hostname' in your tags, create an alias. - -Full Qualified Domain Name (FQDN) - -This validates that a string value contains a valid FQDN. - - Usage: fqdn - -HTML Tags - -This validates that a string value appears to be an HTML element tag -including those described at https://developer.mozilla.org/en-US/docs/Web/HTML/Element - - Usage: html - -HTML Encoded - -This validates that a string value is a proper character reference in decimal -or hexadecimal format - - Usage: html_encoded - -URL Encoded - -This validates that a string value is percent-encoded (URL encoded) according -to https://tools.ietf.org/html/rfc3986#section-2.1 - - Usage: url_encoded - -Directory - -This validates that a string value contains a valid directory and that -it exists on the machine. -This is done using os.Stat, which is a platform independent function. - - Usage: dir - -HostPort - -This validates that a string value contains a valid DNS hostname and port that -can be used to valiate fields typically passed to sockets and connections. - - Usage: hostname_port - -Datetime - -This validates that a string value is a valid datetime based on the supplied datetime format. -Supplied format must match the official Go time format layout as documented in https://golang.org/pkg/time/ - - Usage: datetime=2006-01-02 - -Iso3166-1 alpha-2 - -This validates that a string value is a valid country code based on iso3166-1 alpha-2 standard. -see: https://www.iso.org/iso-3166-country-codes.html - - Usage: iso3166_1_alpha2 - -Iso3166-1 alpha-3 - -This validates that a string value is a valid country code based on iso3166-1 alpha-3 standard. -see: https://www.iso.org/iso-3166-country-codes.html - - Usage: iso3166_1_alpha3 - -Iso3166-1 alpha-numeric - -This validates that a string value is a valid country code based on iso3166-1 alpha-numeric standard. -see: https://www.iso.org/iso-3166-country-codes.html - - Usage: iso3166_1_alpha3 - -TimeZone - -This validates that a string value is a valid time zone based on the time zone database present on the system. -Although empty value and Local value are allowed by time.LoadLocation golang function, they are not allowed by this validator. -More information on https://golang.org/pkg/time/#LoadLocation - - Usage: timezone - - -Alias Validators and Tags - -NOTE: When returning an error, the tag returned in "FieldError" will be -the alias tag unless the dive tag is part of the alias. Everything after the -dive tag is not reported as the alias tag. Also, the "ActualTag" in the before -case will be the actual tag within the alias that failed. - -Here is a list of the current built in alias tags: - - "iscolor" - alias is "hexcolor|rgb|rgba|hsl|hsla" (Usage: iscolor) - "country_code" - alias is "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric" (Usage: country_code) - -Validator notes: - - regex - a regex validator won't be added because commas and = signs can be part - of a regex which conflict with the validation definitions. Although - workarounds can be made, they take away from using pure regex's. - Furthermore it's quick and dirty but the regex's become harder to - maintain and are not reusable, so it's as much a programming philosophy - as anything. - - In place of this new validator functions should be created; a regex can - be used within the validator function and even be precompiled for better - efficiency within regexes.go. - - And the best reason, you can submit a pull request and we can keep on - adding to the validation library of this package! - -Non standard validators - -A collection of validation rules that are frequently needed but are more -complex than the ones found in the baked in validators. -A non standard validator must be registered manually like you would -with your own custom validation functions. - -Example of registration and use: - - type Test struct { - TestField string `validate:"yourtag"` - } - - t := &Test{ - TestField: "Test" - } - - validate := validator.New() - validate.RegisterValidation("yourtag", validators.NotBlank) - -Here is a list of the current non standard validators: - - NotBlank - This validates that the value is not blank or with length zero. - For strings ensures they do not contain only spaces. For channels, maps, slices and arrays - ensures they don't have zero length. For others, a non empty value is required. - - Usage: notblank - -Panics - -This package panics when bad input is provided, this is by design, bad code like -that should not make it to production. - - type Test struct { - TestField string `validate:"nonexistantfunction=1"` - } - - t := &Test{ - TestField: "Test" - } - - validate.Struct(t) // this will panic -*/ -package validator diff --git a/go-playground/validator/v10/errors.go b/go-playground/validator/v10/errors.go deleted file mode 100644 index 3c57b9c..0000000 --- a/go-playground/validator/v10/errors.go +++ /dev/null @@ -1,295 +0,0 @@ -package validator - -import ( - "bytes" - "fmt" - "reflect" - "strings" - - ut "git.ningdatech.com/ningda/gin_valid/go-playground/universal-translator" -) - -const ( - fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag" -) - -// ValidationErrorsTranslations is the translation return type -type ValidationErrorsTranslations map[string]string - -// InvalidValidationError describes an invalid argument passed to -// `Struct`, `StructExcept`, StructPartial` or `Field` -type InvalidValidationError struct { - Type reflect.Type -} - -// Error returns InvalidValidationError message -func (e *InvalidValidationError) Error() string { - - if e.Type == nil { - return "validator: (nil)" - } - - return "validator: (nil " + e.Type.String() + ")" -} - -// ValidationErrors is an array of FieldError's -// for use in custom error messages post validation. -type ValidationErrors []FieldError - -// Error is intended for use in development + debugging and not intended to be a production error message. -// It allows ValidationErrors to subscribe to the Error interface. -// All information to create an error message specific to your application is contained within -// the FieldError found within the ValidationErrors array -func (ve ValidationErrors) Error() string { - - buff := bytes.NewBufferString("") - - var fe *fieldError - - for i := 0; i < len(ve); i++ { - - fe = ve[i].(*fieldError) - buff.WriteString(fe.Error()) - buff.WriteString("\n") - } - - return strings.TrimSpace(buff.String()) -} - -// yang 修改 -// Translate translates all of the ValidationErrors -//func (ve ValidationErrors) Translate(ut ut.Translator) ValidationErrorsTranslations { -// -// trans := make(ValidationErrorsTranslations) -// -// var fe *fieldError -// -// for i := 0; i < len(ve); i++ { -// fe = ve[i].(*fieldError) -// -// // // in case an Anonymous struct was used, ensure that the key -// // // would be 'Username' instead of ".Username" -// // if len(fe.ns) > 0 && fe.ns[:1] == "." { -// // trans[fe.ns[1:]] = fe.Translate(ut) -// // continue -// // } -// -// trans[fe.ns] = fe.Translate(ut) -// } -// -// return trans -//} -type TransValidError struct { - ErrorString string -} - -func (e TransValidError) Error() string { - return e.ErrorString -} -func (ve ValidationErrors) Translate(ut ut.Translator) TransValidError { - var result TransValidError - var fe *fieldError - if len(ve) == 0 { - return result - } - fe = ve[0].(*fieldError) - result.ErrorString = fe.Translate(ut) - return result -} - -// yang修改结束 - -// FieldError contains all functions to get error details -type FieldError interface { - - // returns the validation tag that failed. if the - // validation was an alias, this will return the - // alias name and not the underlying tag that failed. - // - // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla" - // will return "iscolor" - Tag() string - - // returns the validation tag that failed, even if an - // alias the actual tag within the alias will be returned. - // If an 'or' validation fails the entire or will be returned. - // - // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla" - // will return "hexcolor|rgb|rgba|hsl|hsla" - ActualTag() string - - // returns the namespace for the field error, with the tag - // name taking precedence over the field's actual name. - // - // eg. JSON name "User.fname" - // - // See StructNamespace() for a version that returns actual names. - // - // NOTE: this field can be blank when validating a single primitive field - // using validate.Field(...) as there is no way to extract it's name - Namespace() string - - // returns the namespace for the field error, with the field's - // actual name. - // - // eq. "User.FirstName" see Namespace for comparison - // - // NOTE: this field can be blank when validating a single primitive field - // using validate.Field(...) as there is no way to extract its name - StructNamespace() string - - // returns the fields name with the tag name taking precedence over the - // field's actual name. - // - // eq. JSON name "fname" - // see StructField for comparison - Field() string - - // returns the field's actual name from the struct, when able to determine. - // - // eq. "FirstName" - // see Field for comparison - StructField() string - - // returns the actual field's value in case needed for creating the error - // message - Value() interface{} - - // returns the param value, in string form for comparison; this will also - // help with generating an error message - Param() string - - // Kind returns the Field's reflect Kind - // - // eg. time.Time's kind is a struct - Kind() reflect.Kind - - // Type returns the Field's reflect Type - // - // // eg. time.Time's type is time.Time - Type() reflect.Type - - // returns the FieldError's translated error - // from the provided 'ut.Translator' and registered 'TranslationFunc' - // - // NOTE: if no registered translator can be found it returns the same as - // calling fe.Error() - Translate(ut ut.Translator) string - - // Error returns the FieldError's message - Error() string -} - -// compile time interface checks -var _ FieldError = new(fieldError) -var _ error = new(fieldError) - -// fieldError contains a single field's validation error along -// with other properties that may be needed for error message creation -// it complies with the FieldError interface -type fieldError struct { - v *Validate - tag string - actualTag string - ns string - structNs string - fieldLen uint8 - structfieldLen uint8 - value interface{} - param string - kind reflect.Kind - typ reflect.Type -} - -// Tag returns the validation tag that failed. -func (fe *fieldError) Tag() string { - return fe.tag -} - -// ActualTag returns the validation tag that failed, even if an -// alias the actual tag within the alias will be returned. -func (fe *fieldError) ActualTag() string { - return fe.actualTag -} - -// Namespace returns the namespace for the field error, with the tag -// name taking precedence over the field's actual name. -func (fe *fieldError) Namespace() string { - return fe.ns -} - -// StructNamespace returns the namespace for the field error, with the field's -// actual name. -func (fe *fieldError) StructNamespace() string { - return fe.structNs -} - -// Field returns the field's name with the tag name taking precedence over the -// field's actual name. -func (fe *fieldError) Field() string { - - return fe.ns[len(fe.ns)-int(fe.fieldLen):] - // // return fe.field - // fld := fe.ns[len(fe.ns)-int(fe.fieldLen):] - - // log.Println("FLD:", fld) - - // if len(fld) > 0 && fld[:1] == "." { - // return fld[1:] - // } - - // return fld -} - -// returns the field's actual name from the struct, when able to determine. -func (fe *fieldError) StructField() string { - // return fe.structField - return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):] -} - -// Value returns the actual field's value in case needed for creating the error -// message -func (fe *fieldError) Value() interface{} { - return fe.value -} - -// Param returns the param value, in string form for comparison; this will -// also help with generating an error message -func (fe *fieldError) Param() string { - return fe.param -} - -// Kind returns the Field's reflect Kind -func (fe *fieldError) Kind() reflect.Kind { - return fe.kind -} - -// Type returns the Field's reflect Type -func (fe *fieldError) Type() reflect.Type { - return fe.typ -} - -// Error returns the fieldError's error message -func (fe *fieldError) Error() string { - return fmt.Sprintf(fieldErrMsg, fe.ns, fe.Field(), fe.tag) -} - -// Translate returns the FieldError's translated error -// from the provided 'ut.Translator' and registered 'TranslationFunc' -// -// NOTE: if no registered translation can be found, it returns the original -// untranslated error message. -func (fe *fieldError) Translate(ut ut.Translator) string { - - m, ok := fe.v.transTagFunc[ut] - if !ok { - return fe.Error() - } - - fn, ok := m[fe.tag] - if !ok { - return fe.Error() - } - - return fn(ut, fe) -} diff --git a/go-playground/validator/v10/field_level.go b/go-playground/validator/v10/field_level.go deleted file mode 100644 index f0e2a9a..0000000 --- a/go-playground/validator/v10/field_level.go +++ /dev/null @@ -1,119 +0,0 @@ -package validator - -import "reflect" - -// FieldLevel contains all the information and helper functions -// to validate a field -type FieldLevel interface { - // returns the top level struct, if any - Top() reflect.Value - - // returns the current fields parent struct, if any or - // the comparison value if called 'VarWithValue' - Parent() reflect.Value - - // returns current field for validation - Field() reflect.Value - - // returns the field's name with the tag - // name taking precedence over the fields actual name. - FieldName() string - - // returns the struct field's name - StructFieldName() string - - // returns param for validation against current field - Param() string - - // GetTag returns the current validations tag name - GetTag() string - - // ExtractType gets the actual underlying type of field value. - // It will dive into pointers, customTypes and return you the - // underlying value and it's kind. - ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) - - // traverses the parent struct to retrieve a specific field denoted by the provided namespace - // in the param and returns the field, field kind and whether is was successful in retrieving - // the field at all. - // - // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field - // could not be retrieved because it didn't exist. - // - // Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable. - GetStructFieldOK() (reflect.Value, reflect.Kind, bool) - - // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for - // the field and namespace allowing more extensibility for validators. - // - // Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable. - GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) - - // traverses the parent struct to retrieve a specific field denoted by the provided namespace - // in the param and returns the field, field kind, if it's a nullable type and whether is was successful in retrieving - // the field at all. - // - // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field - // could not be retrieved because it didn't exist. - GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) - - // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for - // the field and namespace allowing more extensibility for validators. - GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) -} - -var _ FieldLevel = new(validate) - -// Field returns current field for validation -func (v *validate) Field() reflect.Value { - return v.flField -} - -// FieldName returns the field's name with the tag -// name taking precedence over the fields actual name. -func (v *validate) FieldName() string { - return v.cf.altName -} - -// GetTag returns the current validations tag name -func (v *validate) GetTag() string { - return v.ct.tag -} - -// StructFieldName returns the struct field's name -func (v *validate) StructFieldName() string { - return v.cf.name -} - -// Param returns param for validation against current field -func (v *validate) Param() string { - return v.ct.param -} - -// GetStructFieldOK returns Param returns param for validation against current field -// -// Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable. -func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) { - current, kind, _, found := v.getStructFieldOKInternal(v.slflParent, v.ct.param) - return current, kind, found -} - -// GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for -// the field and namespace allowing more extensibility for validators. -// -// Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable. -func (v *validate) GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) { - current, kind, _, found := v.GetStructFieldOKAdvanced2(val, namespace) - return current, kind, found -} - -// GetStructFieldOK returns Param returns param for validation against current field -func (v *validate) GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) { - return v.getStructFieldOKInternal(v.slflParent, v.ct.param) -} - -// GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for -// the field and namespace allowing more extensibility for validators. -func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) { - return v.getStructFieldOKInternal(val, namespace) -} diff --git a/go-playground/validator/v10/logo.png b/go-playground/validator/v10/logo.png deleted file mode 100644 index 355000f..0000000 Binary files a/go-playground/validator/v10/logo.png and /dev/null differ diff --git a/go-playground/validator/v10/non-standard/validators/notblank.go b/go-playground/validator/v10/non-standard/validators/notblank.go deleted file mode 100644 index 57e71cb..0000000 --- a/go-playground/validator/v10/non-standard/validators/notblank.go +++ /dev/null @@ -1,25 +0,0 @@ -package validators - -import ( - "reflect" - "strings" - - "git.ningdatech.com/ningda/gin_valid/go-playground/validator/v10" -) - -// NotBlank is the validation function for validating if the current field -// has a value or length greater than zero, or is not a space only string. -func NotBlank(fl validator.FieldLevel) bool { - field := fl.Field() - - switch field.Kind() { - case reflect.String: - return len(strings.TrimSpace(field.String())) > 0 - case reflect.Chan, reflect.Map, reflect.Slice, reflect.Array: - return field.Len() > 0 - case reflect.Ptr, reflect.Interface, reflect.Func: - return !field.IsNil() - default: - return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface() - } -} diff --git a/go-playground/validator/v10/regexes.go b/go-playground/validator/v10/regexes.go deleted file mode 100644 index b741f4e..0000000 --- a/go-playground/validator/v10/regexes.go +++ /dev/null @@ -1,101 +0,0 @@ -package validator - -import "regexp" - -const ( - alphaRegexString = "^[a-zA-Z]+$" - alphaNumericRegexString = "^[a-zA-Z0-9]+$" - alphaUnicodeRegexString = "^[\\p{L}]+$" - alphaUnicodeNumericRegexString = "^[\\p{L}\\p{N}]+$" - numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$" - numberRegexString = "^[0-9]+$" - hexadecimalRegexString = "^(0[xX])?[0-9a-fA-F]+$" - hexcolorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" - rgbRegexString = "^rgb\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*\\)$" - rgbaRegexString = "^rgba\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$" - hslRegexString = "^hsl\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*\\)$" - hslaRegexString = "^hsla\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$" - emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" - e164RegexString = "^\\+[1-9]?[0-9]{7,14}$" - base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" - base64URLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2}==|[A-Za-z0-9-_]{3}=|[A-Za-z0-9-_]{4})$" - iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$" - iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$" - uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$" - uUID4RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" - uUID5RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" - uUIDRegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$" - uUID3RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-3[0-9a-fA-F]{3}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" - uUID4RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - uUID5RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-5[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - uUIDRFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" - aSCIIRegexString = "^[\x00-\x7F]*$" - printableASCIIRegexString = "^[\x20-\x7E]*$" - multibyteRegexString = "[^\x00-\x7F]" - dataURIRegexString = `^data:((?:\w+\/(?:([^;]|;[^;]).)+)?)` - latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$" - longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$" - sSNRegexString = `^[0-9]{3}[ -]?(0[1-9]|[1-9][0-9])[ -]?([1-9][0-9]{3}|[0-9][1-9][0-9]{2}|[0-9]{2}[1-9][0-9]|[0-9]{3}[1-9])$` - hostnameRegexStringRFC952 = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$` // https://tools.ietf.org/html/rfc952 - hostnameRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123 - fqdnRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62})(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?(\.[a-zA-Z]{1}[a-zA-Z0-9]{0,62})\.?$` // same as hostnameRegexStringRFC1123 but must contain a non numerical TLD (possibly ending with '.') - btcAddressRegexString = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$` // bitcoin address - btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32 - btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32 - ethAddressRegexString = `^0x[0-9a-fA-F]{40}$` - ethAddressUpperRegexString = `^0x[0-9A-F]{40}$` - ethAddressLowerRegexString = `^0x[0-9a-f]{40}$` - uRLEncodedRegexString = `(%[A-Fa-f0-9]{2})` - hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(>)|(<)|(")|(&)+[;]?` - hTMLRegexString = `<[/]?([a-zA-Z]+).*?>` - splitParamsRegexString = `'[^']*'|\S+` -) - -var ( - alphaRegex = regexp.MustCompile(alphaRegexString) - alphaNumericRegex = regexp.MustCompile(alphaNumericRegexString) - alphaUnicodeRegex = regexp.MustCompile(alphaUnicodeRegexString) - alphaUnicodeNumericRegex = regexp.MustCompile(alphaUnicodeNumericRegexString) - numericRegex = regexp.MustCompile(numericRegexString) - numberRegex = regexp.MustCompile(numberRegexString) - hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString) - hexcolorRegex = regexp.MustCompile(hexcolorRegexString) - rgbRegex = regexp.MustCompile(rgbRegexString) - rgbaRegex = regexp.MustCompile(rgbaRegexString) - hslRegex = regexp.MustCompile(hslRegexString) - hslaRegex = regexp.MustCompile(hslaRegexString) - e164Regex = regexp.MustCompile(e164RegexString) - emailRegex = regexp.MustCompile(emailRegexString) - base64Regex = regexp.MustCompile(base64RegexString) - base64URLRegex = regexp.MustCompile(base64URLRegexString) - iSBN10Regex = regexp.MustCompile(iSBN10RegexString) - iSBN13Regex = regexp.MustCompile(iSBN13RegexString) - uUID3Regex = regexp.MustCompile(uUID3RegexString) - uUID4Regex = regexp.MustCompile(uUID4RegexString) - uUID5Regex = regexp.MustCompile(uUID5RegexString) - uUIDRegex = regexp.MustCompile(uUIDRegexString) - uUID3RFC4122Regex = regexp.MustCompile(uUID3RFC4122RegexString) - uUID4RFC4122Regex = regexp.MustCompile(uUID4RFC4122RegexString) - uUID5RFC4122Regex = regexp.MustCompile(uUID5RFC4122RegexString) - uUIDRFC4122Regex = regexp.MustCompile(uUIDRFC4122RegexString) - aSCIIRegex = regexp.MustCompile(aSCIIRegexString) - printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString) - multibyteRegex = regexp.MustCompile(multibyteRegexString) - dataURIRegex = regexp.MustCompile(dataURIRegexString) - latitudeRegex = regexp.MustCompile(latitudeRegexString) - longitudeRegex = regexp.MustCompile(longitudeRegexString) - sSNRegex = regexp.MustCompile(sSNRegexString) - hostnameRegexRFC952 = regexp.MustCompile(hostnameRegexStringRFC952) - hostnameRegexRFC1123 = regexp.MustCompile(hostnameRegexStringRFC1123) - fqdnRegexRFC1123 = regexp.MustCompile(fqdnRegexStringRFC1123) - btcAddressRegex = regexp.MustCompile(btcAddressRegexString) - btcUpperAddressRegexBech32 = regexp.MustCompile(btcAddressUpperRegexStringBech32) - btcLowerAddressRegexBech32 = regexp.MustCompile(btcAddressLowerRegexStringBech32) - ethAddressRegex = regexp.MustCompile(ethAddressRegexString) - ethaddressRegexUpper = regexp.MustCompile(ethAddressUpperRegexString) - ethAddressRegexLower = regexp.MustCompile(ethAddressLowerRegexString) - uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString) - hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString) - hTMLRegex = regexp.MustCompile(hTMLRegexString) - splitParamsRegex = regexp.MustCompile(splitParamsRegexString) -) diff --git a/go-playground/validator/v10/struct_level.go b/go-playground/validator/v10/struct_level.go deleted file mode 100644 index 57691ee..0000000 --- a/go-playground/validator/v10/struct_level.go +++ /dev/null @@ -1,175 +0,0 @@ -package validator - -import ( - "context" - "reflect" -) - -// StructLevelFunc accepts all values needed for struct level validation -type StructLevelFunc func(sl StructLevel) - -// StructLevelFuncCtx accepts all values needed for struct level validation -// but also allows passing of contextual validation information via context.Context. -type StructLevelFuncCtx func(ctx context.Context, sl StructLevel) - -// wrapStructLevelFunc wraps normal StructLevelFunc makes it compatible with StructLevelFuncCtx -func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx { - return func(ctx context.Context, sl StructLevel) { - fn(sl) - } -} - -// StructLevel contains all the information and helper functions -// to validate a struct -type StructLevel interface { - - // returns the main validation object, in case one wants to call validations internally. - // this is so you don't have to use anonymous functions to get access to the validate - // instance. - Validator() *Validate - - // returns the top level struct, if any - Top() reflect.Value - - // returns the current fields parent struct, if any - Parent() reflect.Value - - // returns the current struct. - Current() reflect.Value - - // ExtractType gets the actual underlying type of field value. - // It will dive into pointers, customTypes and return you the - // underlying value and its kind. - ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) - - // reports an error just by passing the field and tag information - // - // NOTES: - // - // fieldName and altName get appended to the existing namespace that - // validator is on. e.g. pass 'FirstName' or 'Names[0]' depending - // on the nesting - // - // tag can be an existing validation tag or just something you make up - // and process on the flip side it's up to you. - ReportError(field interface{}, fieldName, structFieldName string, tag, param string) - - // reports an error just by passing ValidationErrors - // - // NOTES: - // - // relativeNamespace and relativeActualNamespace get appended to the - // existing namespace that validator is on. - // e.g. pass 'User.FirstName' or 'Users[0].FirstName' depending - // on the nesting. most of the time they will be blank, unless you validate - // at a level lower the the current field depth - ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors) -} - -var _ StructLevel = new(validate) - -// Top returns the top level struct -// -// NOTE: this can be the same as the current struct being validated -// if not is a nested struct. -// -// this is only called when within Struct and Field Level validation and -// should not be relied upon for an acurate value otherwise. -func (v *validate) Top() reflect.Value { - return v.top -} - -// Parent returns the current structs parent -// -// NOTE: this can be the same as the current struct being validated -// if not is a nested struct. -// -// this is only called when within Struct and Field Level validation and -// should not be relied upon for an acurate value otherwise. -func (v *validate) Parent() reflect.Value { - return v.slflParent -} - -// Current returns the current struct. -func (v *validate) Current() reflect.Value { - return v.slCurrent -} - -// Validator returns the main validation object, in case one want to call validations internally. -func (v *validate) Validator() *Validate { - return v.v -} - -// ExtractType gets the actual underlying type of field value. -func (v *validate) ExtractType(field reflect.Value) (reflect.Value, reflect.Kind, bool) { - return v.extractTypeInternal(field, false) -} - -// ReportError reports an error just by passing the field and tag information -func (v *validate) ReportError(field interface{}, fieldName, structFieldName, tag, param string) { - - fv, kind, _ := v.extractTypeInternal(reflect.ValueOf(field), false) - - if len(structFieldName) == 0 { - structFieldName = fieldName - } - - v.str1 = string(append(v.ns, fieldName...)) - - if v.v.hasTagNameFunc || fieldName != structFieldName { - v.str2 = string(append(v.actualNs, structFieldName...)) - } else { - v.str2 = v.str1 - } - - if kind == reflect.Invalid { - - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: tag, - actualTag: tag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(fieldName)), - structfieldLen: uint8(len(structFieldName)), - param: param, - kind: kind, - }, - ) - return - } - - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: tag, - actualTag: tag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(fieldName)), - structfieldLen: uint8(len(structFieldName)), - value: fv.Interface(), - param: param, - kind: kind, - typ: fv.Type(), - }, - ) -} - -// ReportValidationErrors reports ValidationErrors obtained from running validations within the Struct Level validation. -// -// NOTE: this function prepends the current namespace to the relative ones. -func (v *validate) ReportValidationErrors(relativeNamespace, relativeStructNamespace string, errs ValidationErrors) { - - var err *fieldError - - for i := 0; i < len(errs); i++ { - - err = errs[i].(*fieldError) - err.ns = string(append(append(v.ns, relativeNamespace...), err.ns...)) - err.structNs = string(append(append(v.actualNs, relativeStructNamespace...), err.structNs...)) - - v.errs = append(v.errs, err) - } -} diff --git a/go-playground/validator/v10/translations.go b/go-playground/validator/v10/translations.go deleted file mode 100644 index ea58a85..0000000 --- a/go-playground/validator/v10/translations.go +++ /dev/null @@ -1,11 +0,0 @@ -package validator - -import ut "git.ningdatech.com/ningda/gin_valid/go-playground/universal-translator" - -// TranslationFunc is the function type used to register or override -// custom translations -type TranslationFunc func(ut ut.Translator, fe FieldError) string - -// RegisterTranslationsFunc allows for registering of translations -// for a 'ut.Translator' for use within the 'TranslationFunc' -type RegisterTranslationsFunc func(ut ut.Translator) error diff --git a/go-playground/validator/v10/translations/en/en.go b/go-playground/validator/v10/translations/en/en.go deleted file mode 100644 index 1ab53e1..0000000 --- a/go-playground/validator/v10/translations/en/en.go +++ /dev/null @@ -1,1405 +0,0 @@ -package en - -import ( - "fmt" - "log" - "reflect" - "strconv" - "strings" - "time" - - "git.ningdatech.com/ningda/gin_valid/go-playground/locales" - ut "git.ningdatech.com/ningda/gin_valid/go-playground/universal-translator" - "git.ningdatech.com/ningda/gin_valid/go-playground/validator/v10" -) - -// RegisterDefaultTranslations registers a set of default translations -// for all built in tag's in validator; you may add your own as desired. -func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { - - translations := []struct { - tag string - translation string - override bool - customRegisFunc validator.RegisterTranslationsFunc - customTransFunc validator.TranslationFunc - }{ - { - tag: "required", - translation: "{0} is a required field", - override: false, - }, - { - tag: "len", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("len-string", "{0} must be {1} in length", false); err != nil { - return - } - - if err = ut.AddCardinal("len-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("len-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("len-number", "{0} must be equal to {1}", false); err != nil { - return - } - - if err = ut.Add("len-items", "{0} must contain {1}", false); err != nil { - return - } - if err = ut.AddCardinal("len-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("len-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { - return - } - - return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - - var digits uint64 - var kind reflect.Kind - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err := strconv.ParseFloat(fe.Param(), 64) - if err != nil { - goto END - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("len-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("len-items", fe.Field(), c) - - default: - t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("warning: error translating FieldError: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "min", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("min-string", "{0} must be at least {1} in length", false); err != nil { - return - } - - if err = ut.AddCardinal("min-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("min-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("min-number", "{0} must be {1} or greater", false); err != nil { - return - } - - if err = ut.Add("min-items", "{0} must contain at least {1}", false); err != nil { - return - } - if err = ut.AddCardinal("min-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("min-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { - return - } - - return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - - var digits uint64 - var kind reflect.Kind - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err := strconv.ParseFloat(fe.Param(), 64) - if err != nil { - goto END - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("min-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("min-items", fe.Field(), c) - - default: - t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("warning: error translating FieldError: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "max", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("max-string", "{0} must be a maximum of {1} in length", false); err != nil { - return - } - - if err = ut.AddCardinal("max-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("max-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("max-number", "{0} must be {1} or less", false); err != nil { - return - } - - if err = ut.Add("max-items", "{0} must contain at maximum {1}", false); err != nil { - return - } - if err = ut.AddCardinal("max-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("max-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { - return - } - - return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - - var digits uint64 - var kind reflect.Kind - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err := strconv.ParseFloat(fe.Param(), 64) - if err != nil { - goto END - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("max-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("max-items", fe.Field(), c) - - default: - t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("warning: error translating FieldError: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "eq", - translation: "{0} is not equal to {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - fmt.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "ne", - translation: "{0} should not be equal to {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - fmt.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "lt", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("lt-string", "{0} must be less than {1} in length", false); err != nil { - return - } - - if err = ut.AddCardinal("lt-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("lt-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("lt-number", "{0} must be less than {1}", false); err != nil { - return - } - - if err = ut.Add("lt-items", "{0} must contain less than {1}", false); err != nil { - return - } - - if err = ut.AddCardinal("lt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("lt-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("lt-datetime", "{0} must be less than the current Date & Time", false); err != nil { - return - } - - return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - var f64 float64 - var digits uint64 - var kind reflect.Kind - - fn := func() (err error) { - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err = strconv.ParseFloat(fe.Param(), 64) - - return - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("lt-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("lt-items", fe.Field(), c) - - case reflect.Struct: - if fe.Type() != reflect.TypeOf(time.Time{}) { - err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) - goto END - } - - t, err = ut.T("lt-datetime", fe.Field()) - - default: - err = fn() - if err != nil { - goto END - } - - t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("warning: error translating FieldError: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "lte", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("lte-string", "{0} must be at maximum {1} in length", false); err != nil { - return - } - - if err = ut.AddCardinal("lte-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("lte-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("lte-number", "{0} must be {1} or less", false); err != nil { - return - } - - if err = ut.Add("lte-items", "{0} must contain at maximum {1}", false); err != nil { - return - } - - if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("lte-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("lte-datetime", "{0} must be less than or equal to the current Date & Time", false); err != nil { - return - } - - return - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - var f64 float64 - var digits uint64 - var kind reflect.Kind - - fn := func() (err error) { - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err = strconv.ParseFloat(fe.Param(), 64) - - return - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("lte-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("lte-items", fe.Field(), c) - - case reflect.Struct: - if fe.Type() != reflect.TypeOf(time.Time{}) { - err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) - goto END - } - - t, err = ut.T("lte-datetime", fe.Field()) - - default: - err = fn() - if err != nil { - goto END - } - - t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("warning: error translating FieldError: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "gt", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("gt-string", "{0} must be greater than {1} in length", false); err != nil { - return - } - - if err = ut.AddCardinal("gt-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("gt-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("gt-number", "{0} must be greater than {1}", false); err != nil { - return - } - - if err = ut.Add("gt-items", "{0} must contain more than {1}", false); err != nil { - return - } - - if err = ut.AddCardinal("gt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("gt-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("gt-datetime", "{0} must be greater than the current Date & Time", false); err != nil { - return - } - - return - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - var f64 float64 - var digits uint64 - var kind reflect.Kind - - fn := func() (err error) { - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err = strconv.ParseFloat(fe.Param(), 64) - - return - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("gt-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("gt-items", fe.Field(), c) - - case reflect.Struct: - if fe.Type() != reflect.TypeOf(time.Time{}) { - err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) - goto END - } - - t, err = ut.T("gt-datetime", fe.Field()) - - default: - err = fn() - if err != nil { - goto END - } - - t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("warning: error translating FieldError: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "gte", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("gte-string", "{0} must be at least {1} in length", false); err != nil { - return - } - - if err = ut.AddCardinal("gte-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("gte-string-character", "{0} characters", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("gte-number", "{0} must be {1} or greater", false); err != nil { - return - } - - if err = ut.Add("gte-items", "{0} must contain at least {1}", false); err != nil { - return - } - - if err = ut.AddCardinal("gte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - return - } - - if err = ut.AddCardinal("gte-items-item", "{0} items", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("gte-datetime", "{0} must be greater than or equal to the current Date & Time", false); err != nil { - return - } - - return - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - var f64 float64 - var digits uint64 - var kind reflect.Kind - - fn := func() (err error) { - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err = strconv.ParseFloat(fe.Param(), 64) - - return - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("gte-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("gte-items", fe.Field(), c) - - case reflect.Struct: - if fe.Type() != reflect.TypeOf(time.Time{}) { - err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) - goto END - } - - t, err = ut.T("gte-datetime", fe.Field()) - - default: - err = fn() - if err != nil { - goto END - } - - t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("warning: error translating FieldError: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "eqfield", - translation: "{0} must be equal to {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "eqcsfield", - translation: "{0} must be equal to {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "necsfield", - translation: "{0} cannot be equal to {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "gtcsfield", - translation: "{0} must be greater than {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "gtecsfield", - translation: "{0} must be greater than or equal to {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "ltcsfield", - translation: "{0} must be less than {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "ltecsfield", - translation: "{0} must be less than or equal to {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "nefield", - translation: "{0} cannot be equal to {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "gtfield", - translation: "{0} must be greater than {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "gtefield", - translation: "{0} must be greater than or equal to {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "ltfield", - translation: "{0} must be less than {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "ltefield", - translation: "{0} must be less than or equal to {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "alpha", - translation: "{0} can only contain alphabetic characters", - override: false, - }, - { - tag: "alphanum", - translation: "{0} can only contain alphanumeric characters", - override: false, - }, - { - tag: "numeric", - translation: "{0} must be a valid numeric value", - override: false, - }, - { - tag: "number", - translation: "{0} must be a valid number", - override: false, - }, - { - tag: "hexadecimal", - translation: "{0} must be a valid hexadecimal", - override: false, - }, - { - tag: "hexcolor", - translation: "{0} must be a valid HEX color", - override: false, - }, - { - tag: "rgb", - translation: "{0} must be a valid RGB color", - override: false, - }, - { - tag: "rgba", - translation: "{0} must be a valid RGBA color", - override: false, - }, - { - tag: "hsl", - translation: "{0} must be a valid HSL color", - override: false, - }, - { - tag: "hsla", - translation: "{0} must be a valid HSLA color", - override: false, - }, - { - tag: "e164", - translation: "{0} must be a valid E.164 formatted phone number", - override: false, - }, - { - tag: "email", - translation: "{0} must be a valid email address", - override: false, - }, - { - tag: "url", - translation: "{0} must be a valid URL", - override: false, - }, - { - tag: "uri", - translation: "{0} must be a valid URI", - override: false, - }, - { - tag: "base64", - translation: "{0} must be a valid Base64 string", - override: false, - }, - { - tag: "contains", - translation: "{0} must contain the text '{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "containsany", - translation: "{0} must contain at least one of the following characters '{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "excludes", - translation: "{0} cannot contain the text '{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "excludesall", - translation: "{0} cannot contain any of the following characters '{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "excludesrune", - translation: "{0} cannot contain the following '{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "isbn", - translation: "{0} must be a valid ISBN number", - override: false, - }, - { - tag: "isbn10", - translation: "{0} must be a valid ISBN-10 number", - override: false, - }, - { - tag: "isbn13", - translation: "{0} must be a valid ISBN-13 number", - override: false, - }, - { - tag: "uuid", - translation: "{0} must be a valid UUID", - override: false, - }, - { - tag: "uuid3", - translation: "{0} must be a valid version 3 UUID", - override: false, - }, - { - tag: "uuid4", - translation: "{0} must be a valid version 4 UUID", - override: false, - }, - { - tag: "uuid5", - translation: "{0} must be a valid version 5 UUID", - override: false, - }, - { - tag: "ascii", - translation: "{0} must contain only ascii characters", - override: false, - }, - { - tag: "printascii", - translation: "{0} must contain only printable ascii characters", - override: false, - }, - { - tag: "multibyte", - translation: "{0} must contain multibyte characters", - override: false, - }, - { - tag: "datauri", - translation: "{0} must contain a valid Data URI", - override: false, - }, - { - tag: "latitude", - translation: "{0} must contain valid latitude coordinates", - override: false, - }, - { - tag: "longitude", - translation: "{0} must contain a valid longitude coordinates", - override: false, - }, - { - tag: "ssn", - translation: "{0} must be a valid SSN number", - override: false, - }, - { - tag: "ipv4", - translation: "{0} must be a valid IPv4 address", - override: false, - }, - { - tag: "ipv6", - translation: "{0} must be a valid IPv6 address", - override: false, - }, - { - tag: "ip", - translation: "{0} must be a valid IP address", - override: false, - }, - { - tag: "cidr", - translation: "{0} must contain a valid CIDR notation", - override: false, - }, - { - tag: "cidrv4", - translation: "{0} must contain a valid CIDR notation for an IPv4 address", - override: false, - }, - { - tag: "cidrv6", - translation: "{0} must contain a valid CIDR notation for an IPv6 address", - override: false, - }, - { - tag: "tcp_addr", - translation: "{0} must be a valid TCP address", - override: false, - }, - { - tag: "tcp4_addr", - translation: "{0} must be a valid IPv4 TCP address", - override: false, - }, - { - tag: "tcp6_addr", - translation: "{0} must be a valid IPv6 TCP address", - override: false, - }, - { - tag: "udp_addr", - translation: "{0} must be a valid UDP address", - override: false, - }, - { - tag: "udp4_addr", - translation: "{0} must be a valid IPv4 UDP address", - override: false, - }, - { - tag: "udp6_addr", - translation: "{0} must be a valid IPv6 UDP address", - override: false, - }, - { - tag: "ip_addr", - translation: "{0} must be a resolvable IP address", - override: false, - }, - { - tag: "ip4_addr", - translation: "{0} must be a resolvable IPv4 address", - override: false, - }, - { - tag: "ip6_addr", - translation: "{0} must be a resolvable IPv6 address", - override: false, - }, - { - tag: "unix_addr", - translation: "{0} must be a resolvable UNIX address", - override: false, - }, - { - tag: "mac", - translation: "{0} must contain a valid MAC address", - override: false, - }, - { - tag: "unique", - translation: "{0} must contain unique values", - override: false, - }, - { - tag: "iscolor", - translation: "{0} must be a valid color", - override: false, - }, - { - tag: "oneof", - translation: "{0} must be one of [{1}]", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - return s - }, - }, - { - tag: "json", - translation: "{0} must be a valid json string", - override: false, - }, - { - tag: "lowercase", - translation: "{0} must be a lowercase string", - override: false, - }, - { - tag: "uppercase", - translation: "{0} must be an uppercase string", - override: false, - }, - { - tag: "datetime", - translation: "{0} does not match the {1} format", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - } - - for _, t := range translations { - - if t.customTransFunc != nil && t.customRegisFunc != nil { - - err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) - - } else if t.customTransFunc != nil && t.customRegisFunc == nil { - - err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) - - } else if t.customTransFunc == nil && t.customRegisFunc != nil { - - err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) - - } else { - err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) - } - - if err != nil { - return - } - } - - return -} - -func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { - - return func(ut ut.Translator) (err error) { - - if err = ut.Add(tag, translation, override); err != nil { - return - } - - return - - } - -} - -func translateFunc(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t -} diff --git a/go-playground/validator/v10/translations/zh/zh.go b/go-playground/validator/v10/translations/zh/zh.go deleted file mode 100644 index a954e8b..0000000 --- a/go-playground/validator/v10/translations/zh/zh.go +++ /dev/null @@ -1,1392 +0,0 @@ -package zh - -import ( - "fmt" - "git.ningdatech.com/ningda/gin_valid/go-playground/validator/v10" - "log" - "reflect" - "strconv" - "strings" - "time" - - "git.ningdatech.com/ningda/gin_valid/go-playground/locales" - ut "git.ningdatech.com/ningda/gin_valid/go-playground/universal-translator" -) - -// RegisterDefaultTranslations registers a set of default translations -// for all built in tag's in validator; you may add your own as desired. -func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { - - translations := []struct { - tag string - translation string - override bool - customRegisFunc validator.RegisterTranslationsFunc - customTransFunc validator.TranslationFunc - }{ - { - tag: "required", - translation: "{0}为必填字段", - override: false, - }, - { - tag: "len", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("len-string", "{0}长度必须是{1}", false); err != nil { - return - } - - //if err = ut.AddCardinal("len-string-character", "{0}字符", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("len-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("len-number", "{0}必须等于{1}", false); err != nil { - return - } - - if err = ut.Add("len-items", "{0}必须包含{1}", false); err != nil { - return - } - //if err = ut.AddCardinal("len-items-item", "{0}项", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("len-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { - return - } - - return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - - var digits uint64 - var kind reflect.Kind - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err := strconv.ParseFloat(fe.Param(), 64) - if err != nil { - goto END - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("len-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("len-items", fe.Field(), c) - - default: - t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("警告: 翻译字段错误: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "min", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("min-string", "{0}长度必须至少为{1}", false); err != nil { - return - } - - //if err = ut.AddCardinal("min-string-character", "{0}个字符", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("min-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("min-number", "{0}最小只能为{1}", false); err != nil { - return - } - - if err = ut.Add("min-items", "{0}必须至少包含{1}", false); err != nil { - return - } - //if err = ut.AddCardinal("min-items-item", "{0}项", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("min-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { - return - } - - return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - - var digits uint64 - var kind reflect.Kind - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err := strconv.ParseFloat(fe.Param(), 64) - if err != nil { - goto END - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("min-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("min-items", fe.Field(), c) - - default: - t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("警告: 翻译字段错误: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "max", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("max-string", "{0}长度不能超过{1}", false); err != nil { - return - } - - //if err = ut.AddCardinal("max-string-character", "{0}个字符", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("max-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("max-number", "{0}必须小于或等于{1}", false); err != nil { - return - } - - if err = ut.Add("max-items", "{0}最多只能包含{1}", false); err != nil { - return - } - //if err = ut.AddCardinal("max-items-item", "{0}项", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("max-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { - return - } - - return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - - var digits uint64 - var kind reflect.Kind - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err := strconv.ParseFloat(fe.Param(), 64) - if err != nil { - goto END - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("max-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("max-items", fe.Field(), c) - - default: - t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("警告: 翻译字段错误: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "eq", - translation: "{0}不等于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - fmt.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "ne", - translation: "{0}不能等于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - fmt.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "lt", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("lt-string", "{0}长度必须小于{1}", false); err != nil { - return - } - - //if err = ut.AddCardinal("lt-string-character", "{0}个字符", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("lt-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("lt-number", "{0}必须小于{1}", false); err != nil { - return - } - - if err = ut.Add("lt-items", "{0}必须包含少于{1}", false); err != nil { - return - } - - //if err = ut.AddCardinal("lt-items-item", "{0}项", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("lt-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("lt-datetime", "{0}必须小于当前日期和时间", false); err != nil { - return - } - - return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - var f64 float64 - var digits uint64 - var kind reflect.Kind - - fn := func() (err error) { - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err = strconv.ParseFloat(fe.Param(), 64) - - return - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("lt-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("lt-items", fe.Field(), c) - - case reflect.Struct: - if fe.Type() != reflect.TypeOf(time.Time{}) { - err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag()) - } else { - t, err = ut.T("lt-datetime", fe.Field()) - } - - default: - err = fn() - if err != nil { - goto END - } - - t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("警告: 翻译字段错误: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "lte", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("lte-string", "{0}长度不能超过{1}", false); err != nil { - return - } - - //if err = ut.AddCardinal("lte-string-character", "{0} character", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("lte-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("lte-number", "{0}必须小于或等于{1}", false); err != nil { - return - } - - if err = ut.Add("lte-items", "{0}最多只能包含{1}", false); err != nil { - return - } - - //if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("lte-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("lte-datetime", "{0}必须小于或等于当前日期和时间", false); err != nil { - return - } - - return - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - var f64 float64 - var digits uint64 - var kind reflect.Kind - - fn := func() (err error) { - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err = strconv.ParseFloat(fe.Param(), 64) - - return - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("lte-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("lte-items", fe.Field(), c) - - case reflect.Struct: - if fe.Type() != reflect.TypeOf(time.Time{}) { - err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag()) - } else { - t, err = ut.T("lte-datetime", fe.Field()) - } - - default: - err = fn() - if err != nil { - goto END - } - - t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("警告: 翻译字段错误: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "gt", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("gt-string", "{0}长度必须大于{1}", false); err != nil { - return - } - - //if err = ut.AddCardinal("gt-string-character", "{0}个字符", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("gt-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("gt-number", "{0}必须大于{1}", false); err != nil { - return - } - - if err = ut.Add("gt-items", "{0}必须大于{1}", false); err != nil { - return - } - - //if err = ut.AddCardinal("gt-items-item", "{0}项", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("gt-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("gt-datetime", "{0}必须大于当前日期和时间", false); err != nil { - return - } - - return - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - var f64 float64 - var digits uint64 - var kind reflect.Kind - - fn := func() (err error) { - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err = strconv.ParseFloat(fe.Param(), 64) - - return - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("gt-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("gt-items", fe.Field(), c) - - case reflect.Struct: - if fe.Type() != reflect.TypeOf(time.Time{}) { - err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag()) - } else { - - t, err = ut.T("gt-datetime", fe.Field()) - } - - default: - err = fn() - if err != nil { - goto END - } - - t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("警告: 翻译字段错误: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "gte", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("gte-string", "{0}长度必须至少为{1}", false); err != nil { - return - } - - //if err = ut.AddCardinal("gte-string-character", "{0}个字符", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("gte-string-character", "{0}个字符", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("gte-number", "{0}必须大于或等于{1}", false); err != nil { - return - } - - if err = ut.Add("gte-items", "{0}必须至少包含{1}", false); err != nil { - return - } - - //if err = ut.AddCardinal("gte-items-item", "{0}项", locales.PluralRuleOne, false); err != nil { - // return - //} - - if err = ut.AddCardinal("gte-items-item", "{0}项", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("gte-datetime", "{0}必须大于或等于当前日期和时间", false); err != nil { - return - } - - return - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - var f64 float64 - var digits uint64 - var kind reflect.Kind - - fn := func() (err error) { - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) // 表示小数部分的位数 - } - - f64, err = strconv.ParseFloat(fe.Param(), 64) - - return - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("gte-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - err = fn() - if err != nil { - goto END - } - - c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("gte-items", fe.Field(), c) - - case reflect.Struct: - if fe.Type() != reflect.TypeOf(time.Time{}) { - err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag()) - } else { - t, err = ut.T("gte-datetime", fe.Field()) - } - - default: - err = fn() - if err != nil { - goto END - } - - t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("警告: 翻译字段错误: %s", err) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "eqfield", - translation: "{0}必须等于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "eqcsfield", - translation: "{0}必须等于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "necsfield", - translation: "{0}不能等于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "gtcsfield", - translation: "{0}必须大于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "gtecsfield", - translation: "{0}必须大于或等于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "ltcsfield", - translation: "{0}必须小于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "ltecsfield", - translation: "{0}必须小于或等于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "nefield", - translation: "{0}不能等于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "gtfield", - translation: "{0}必须大于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "gtefield", - translation: "{0}必须大于或等于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "ltfield", - translation: "{0}必须小于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "ltefield", - translation: "{0}必须小于或等于{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "alpha", - translation: "{0}只能包含字母", - override: false, - }, - { - tag: "alphanum", - translation: "{0}只能包含字母和数字", - override: false, - }, - { - tag: "numeric", - translation: "{0}必须是一个有效的数值", - override: false, - }, - { - tag: "number", - translation: "{0}必须是一个有效的数字", - override: false, - }, - { - tag: "hexadecimal", - translation: "{0}必须是一个有效的十六进制", - override: false, - }, - { - tag: "hexcolor", - translation: "{0}必须是一个有效的十六进制颜色", - override: false, - }, - { - tag: "rgb", - translation: "{0}必须是一个有效的RGB颜色", - override: false, - }, - { - tag: "rgba", - translation: "{0}必须是一个有效的RGBA颜色", - override: false, - }, - { - tag: "hsl", - translation: "{0}必须是一个有效的HSL颜色", - override: false, - }, - { - tag: "hsla", - translation: "{0}必须是一个有效的HSLA颜色", - override: false, - }, - { - tag: "email", - translation: "{0}必须是一个有效的邮箱", - override: false, - }, - { - tag: "url", - translation: "{0}必须是一个有效的URL", - override: false, - }, - { - tag: "uri", - translation: "{0}必须是一个有效的URI", - override: false, - }, - { - tag: "base64", - translation: "{0}必须是一个有效的Base64字符串", - override: false, - }, - { - tag: "contains", - translation: "{0}必须包含文本'{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "containsany", - translation: "{0}必须包含至少一个以下字符'{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "excludes", - translation: "{0}不能包含文本'{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "excludesall", - translation: "{0}不能包含以下任何字符'{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "excludesrune", - translation: "{0}不能包含'{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - { - tag: "isbn", - translation: "{0}必须是一个有效的ISBN编号", - override: false, - }, - { - tag: "isbn10", - translation: "{0}必须是一个有效的ISBN-10编号", - override: false, - }, - { - tag: "isbn13", - translation: "{0}必须是一个有效的ISBN-13编号", - override: false, - }, - { - tag: "uuid", - translation: "{0}必须是一个有效的UUID", - override: false, - }, - { - tag: "uuid3", - translation: "{0}必须是一个有效的V3 UUID", - override: false, - }, - { - tag: "uuid4", - translation: "{0}必须是一个有效的V4 UUID", - override: false, - }, - { - tag: "uuid5", - translation: "{0}必须是一个有效的V5 UUID", - override: false, - }, - { - tag: "ascii", - translation: "{0}必须只包含ascii字符", - override: false, - }, - { - tag: "printascii", - translation: "{0}必须只包含可打印的ascii字符", - override: false, - }, - { - tag: "multibyte", - translation: "{0}必须包含多字节字符", - override: false, - }, - { - tag: "datauri", - translation: "{0}必须包含有效的数据URI", - override: false, - }, - { - tag: "latitude", - translation: "{0}必须包含有效的纬度坐标", - override: false, - }, - { - tag: "longitude", - translation: "{0}必须包含有效的经度坐标", - override: false, - }, - { - tag: "ssn", - translation: "{0}必须是一个有效的社会安全号码(SSN)", - override: false, - }, - { - tag: "ipv4", - translation: "{0}必须是一个有效的IPv4地址", - override: false, - }, - { - tag: "ipv6", - translation: "{0}必须是一个有效的IPv6地址", - override: false, - }, - { - tag: "ip", - translation: "{0}必须是一个有效的IP地址", - override: false, - }, - { - tag: "cidr", - translation: "{0}必须是一个有效的无类别域间路由(CIDR)", - override: false, - }, - { - tag: "cidrv4", - translation: "{0}必须是一个包含IPv4地址的有效无类别域间路由(CIDR)", - override: false, - }, - { - tag: "cidrv6", - translation: "{0}必须是一个包含IPv6地址的有效无类别域间路由(CIDR)", - override: false, - }, - { - tag: "tcp_addr", - translation: "{0}必须是一个有效的TCP地址", - override: false, - }, - { - tag: "tcp4_addr", - translation: "{0}必须是一个有效的IPv4 TCP地址", - override: false, - }, - { - tag: "tcp6_addr", - translation: "{0}必须是一个有效的IPv6 TCP地址", - override: false, - }, - { - tag: "udp_addr", - translation: "{0}必须是一个有效的UDP地址", - override: false, - }, - { - tag: "udp4_addr", - translation: "{0}必须是一个有效的IPv4 UDP地址", - override: false, - }, - { - tag: "udp6_addr", - translation: "{0}必须是一个有效的IPv6 UDP地址", - override: false, - }, - { - tag: "ip_addr", - translation: "{0}必须是一个有效的IP地址", - override: false, - }, - { - tag: "ip4_addr", - translation: "{0}必须是一个有效的IPv4地址", - override: false, - }, - { - tag: "ip6_addr", - translation: "{0}必须是一个有效的IPv6地址", - override: false, - }, - { - tag: "unix_addr", - translation: "{0}必须是一个有效的UNIX地址", - override: false, - }, - { - tag: "mac", - translation: "{0}必须是一个有效的MAC地址", - override: false, - }, - { - tag: "iscolor", - translation: "{0}必须是一个有效的颜色", - override: false, - }, - { - tag: "oneof", - translation: "{0}必须是[{1}]中的一个", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - return s - }, - }, - { - tag: "json", - translation: "{0}必须是一个JSON字符串", - override: false, - }, - { - tag: "lowercase", - translation: "{0}必须是小写字母", - override: false, - }, - { - tag: "uppercase", - translation: "{0}必须是大写字母", - override: false, - }, - { - tag: "datetime", - translation: "{0}的格式必须是{1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t - }, - }, - } - - for _, t := range translations { - - if t.customTransFunc != nil && t.customRegisFunc != nil { - - err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) - - } else if t.customTransFunc != nil && t.customRegisFunc == nil { - - err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) - - } else if t.customTransFunc == nil && t.customRegisFunc != nil { - - err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) - - } else { - err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) - } - - if err != nil { - return - } - } - - return -} - -func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { - - return func(ut ut.Translator) (err error) { - - if err = ut.Add(tag, translation, override); err != nil { - return - } - - return - - } - -} - -func translateFunc(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field()) - if err != nil { - log.Printf("警告: 翻译字段错误: %#v", fe) - return fe.(error).Error() - } - - return t -} diff --git a/go-playground/validator/v10/util.go b/go-playground/validator/v10/util.go deleted file mode 100644 index cb564e3..0000000 --- a/go-playground/validator/v10/util.go +++ /dev/null @@ -1,288 +0,0 @@ -package validator - -import ( - "reflect" - "strconv" - "strings" - "time" -) - -// extractTypeInternal gets the actual underlying type of field value. -// It will dive into pointers, customTypes and return you the -// underlying value and it's kind. -func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) { - -BEGIN: - switch current.Kind() { - case reflect.Ptr: - - nullable = true - - if current.IsNil() { - return current, reflect.Ptr, nullable - } - - current = current.Elem() - goto BEGIN - - case reflect.Interface: - - nullable = true - - if current.IsNil() { - return current, reflect.Interface, nullable - } - - current = current.Elem() - goto BEGIN - - case reflect.Invalid: - return current, reflect.Invalid, nullable - - default: - - if v.v.hasCustomFuncs { - - if fn, ok := v.v.customFuncs[current.Type()]; ok { - current = reflect.ValueOf(fn(current)) - goto BEGIN - } - } - - return current, current.Kind(), nullable - } -} - -// getStructFieldOKInternal traverses a struct to retrieve a specific field denoted by the provided namespace and -// returns the field, field kind and whether is was successful in retrieving the field at all. -// -// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field -// could not be retrieved because it didn't exist. -func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, nullable bool, found bool) { - // val 是结构体, 如果 gtfield=filed1 这种field的比较,那 namespace就是入参 filed1 -BEGIN: - current, kind, nullable = v.ExtractType(val) - if kind == reflect.Invalid { - return - } - - if namespace == "" { - found = true - return - } - - switch kind { - - case reflect.Ptr, reflect.Interface: - return - - case reflect.Struct: - - typ := current.Type() - fld := namespace - var ns string - - if typ != timeType { - - idx := strings.Index(namespace, namespaceSeparator) - - if idx != -1 { - fld = namespace[:idx] - ns = namespace[idx+1:] - } else { - ns = "" - } - - bracketIdx := strings.Index(fld, leftBracket) - if bracketIdx != -1 { - fld = fld[:bracketIdx] - - ns = namespace[bracketIdx:] - } - - val = current.FieldByName(fld) - namespace = ns - goto BEGIN - } - - case reflect.Array, reflect.Slice: - idx := strings.Index(namespace, leftBracket) - idx2 := strings.Index(namespace, rightBracket) - - arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2]) - - if arrIdx >= current.Len() { - return - } - - startIdx := idx2 + 1 - - if startIdx < len(namespace) { - if namespace[startIdx:startIdx+1] == namespaceSeparator { - startIdx++ - } - } - - val = current.Index(arrIdx) - namespace = namespace[startIdx:] - goto BEGIN - - case reflect.Map: - idx := strings.Index(namespace, leftBracket) + 1 - idx2 := strings.Index(namespace, rightBracket) - - endIdx := idx2 - - if endIdx+1 < len(namespace) { - if namespace[endIdx+1:endIdx+2] == namespaceSeparator { - endIdx++ - } - } - - key := namespace[idx:idx2] - - switch current.Type().Key().Kind() { - case reflect.Int: - i, _ := strconv.Atoi(key) - val = current.MapIndex(reflect.ValueOf(i)) - namespace = namespace[endIdx+1:] - - case reflect.Int8: - i, _ := strconv.ParseInt(key, 10, 8) - val = current.MapIndex(reflect.ValueOf(int8(i))) - namespace = namespace[endIdx+1:] - - case reflect.Int16: - i, _ := strconv.ParseInt(key, 10, 16) - val = current.MapIndex(reflect.ValueOf(int16(i))) - namespace = namespace[endIdx+1:] - - case reflect.Int32: - i, _ := strconv.ParseInt(key, 10, 32) - val = current.MapIndex(reflect.ValueOf(int32(i))) - namespace = namespace[endIdx+1:] - - case reflect.Int64: - i, _ := strconv.ParseInt(key, 10, 64) - val = current.MapIndex(reflect.ValueOf(i)) - namespace = namespace[endIdx+1:] - - case reflect.Uint: - i, _ := strconv.ParseUint(key, 10, 0) - val = current.MapIndex(reflect.ValueOf(uint(i))) - namespace = namespace[endIdx+1:] - - case reflect.Uint8: - i, _ := strconv.ParseUint(key, 10, 8) - val = current.MapIndex(reflect.ValueOf(uint8(i))) - namespace = namespace[endIdx+1:] - - case reflect.Uint16: - i, _ := strconv.ParseUint(key, 10, 16) - val = current.MapIndex(reflect.ValueOf(uint16(i))) - namespace = namespace[endIdx+1:] - - case reflect.Uint32: - i, _ := strconv.ParseUint(key, 10, 32) - val = current.MapIndex(reflect.ValueOf(uint32(i))) - namespace = namespace[endIdx+1:] - - case reflect.Uint64: - i, _ := strconv.ParseUint(key, 10, 64) - val = current.MapIndex(reflect.ValueOf(i)) - namespace = namespace[endIdx+1:] - - case reflect.Float32: - f, _ := strconv.ParseFloat(key, 32) - val = current.MapIndex(reflect.ValueOf(float32(f))) - namespace = namespace[endIdx+1:] - - case reflect.Float64: - f, _ := strconv.ParseFloat(key, 64) - val = current.MapIndex(reflect.ValueOf(f)) - namespace = namespace[endIdx+1:] - - case reflect.Bool: - b, _ := strconv.ParseBool(key) - val = current.MapIndex(reflect.ValueOf(b)) - namespace = namespace[endIdx+1:] - - // reflect.Type = string - default: - val = current.MapIndex(reflect.ValueOf(key)) - namespace = namespace[endIdx+1:] - } - - goto BEGIN - } - - // if got here there was more namespace, cannot go any deeper - panic("Invalid field namespace") -} - -// asInt returns the parameter as a int64 -// or panics if it can't convert -func asInt(param string) int64 { - i, err := strconv.ParseInt(param, 0, 64) - panicIf(err) - - return i -} - -// asIntFromTimeDuration parses param as time.Duration and returns it as int64 -// or panics on error. -func asIntFromTimeDuration(param string) int64 { - d, err := time.ParseDuration(param) - if err != nil { - // attempt parsing as an an integer assuming nanosecond precision - return asInt(param) - } - return int64(d) -} - -// asIntFromType calls the proper function to parse param as int64, -// given a field's Type t. -func asIntFromType(t reflect.Type, param string) int64 { - switch t { - case timeDurationType: - return asIntFromTimeDuration(param) - default: - return asInt(param) - } -} - -// asUint returns the parameter as a uint64 -// or panics if it can't convert -func asUint(param string) uint64 { - - i, err := strconv.ParseUint(param, 0, 64) - panicIf(err) - - return i -} - -// asFloat returns the parameter as a float64 -// or panics if it can't convert -func asFloat(param string) float64 { - - i, err := strconv.ParseFloat(param, 64) - panicIf(err) - - return i -} - -// asBool returns the parameter as a bool -// or panics if it can't convert -func asBool(param string) bool { - - i, err := strconv.ParseBool(param) - panicIf(err) - - return i -} - -func panicIf(err error) { - if err != nil { - panic(err.Error()) - } -} diff --git a/go-playground/validator/v10/validator.go b/go-playground/validator/v10/validator.go deleted file mode 100644 index 5baacfe..0000000 --- a/go-playground/validator/v10/validator.go +++ /dev/null @@ -1,482 +0,0 @@ -package validator - -import ( - "context" - "fmt" - "reflect" - "strconv" -) - -// per validate construct -type validate struct { - v *Validate - top reflect.Value - ns []byte // ns是命名空间,见 - actualNs []byte - // 如果想修改 错误信息的打印, 直接改这个错误的 .Error()方法应该就可以了, 不对不对,还有一个翻译在执行 - errs ValidationErrors //校验失败的 记录错误的 结构体的 field[] , 依次验证field,所以可以加个判断,只要有一个错误,就停下来 //每次用完都会清零,在put回pool - includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise - ffn FilterFunc - slflParent reflect.Value // StructLevel & FieldLevel - slCurrent reflect.Value // StructLevel & FieldLevel - flField reflect.Value // StructLevel & FieldLevel - cf *cField // StructLevel & FieldLevel - ct *cTag // StructLevel & FieldLevel - misc []byte // misc reusable - str1 string // misc reusable // 真正显示的 错误,有别名就是别名 - str2 string // misc reusable // 失败的field信息,如 User.Name (结构体名称+field真名称),如果没有别名,就是str1 - fldIsPointer bool // StructLevel & FieldLevel - isPartial bool - hasExcludes bool -} - -// parent and current will be the same the first run of validateStruct -func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, structNs []byte, ct *cTag) { - - cs, ok := v.v.structCache.Get(typ) - if !ok { - cs = v.v.extractStructCache(current, typ.Name()) - } - - if len(ns) == 0 && len(cs.name) != 0 { - // 但实际上,`:` 左边的我都不需要,所以还是改 翻译 比较好 , 而且可能会影响到 未知的错误 - ns = append(ns, cs.name...) // 去掉这里的ns的内容,出现错误时,应该就就不会输出 struct.field:"err", 而是 field:"err", - ns = append(ns, '.') - - structNs = append(structNs, cs.name...) - structNs = append(structNs, '.') - } - - // ct is nil on top level struct, and structs as fields that have no tag info - // so if nil or if not nil and the structonly tag isn't present - if ct == nil || ct.typeof != typeStructOnly { - - var f *cField - - for i := 0; i < len(cs.fields); i++ { - // yang 加个判断, 有一个验证不通过就退出 - if len(v.errs) != 0 { - break - } - // yang 修改分割线 - f = cs.fields[i] - - if v.isPartial { - - if v.ffn != nil { - // used with StructFiltered - if v.ffn(append(structNs, f.name...)) { - continue - } - - } else { - // used with StructPartial & StructExcept - _, ok = v.includeExclude[string(append(structNs, f.name...))] - - if (ok && v.hasExcludes) || (!ok && !v.hasExcludes) { - continue - } - } - } - - v.traverseField(ctx, parent, current.Field(f.idx), ns, structNs, f, f.cTags) - } - } - - // check if any struct level validations, after all field validations already checked. - // first iteration will have no info about nostructlevel tag, and is checked prior to - // calling the next iteration of validateStruct called from traverseField. - if cs.fn != nil { - - v.slflParent = parent - v.slCurrent = current - v.ns = ns - v.actualNs = structNs - - cs.fn(ctx, v) - } -} - -// traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options -func (v *validate) traverseField(ctx context.Context, parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) { - var typ reflect.Type - var kind reflect.Kind - - current, kind, v.fldIsPointer = v.extractTypeInternal(current, false) - - switch kind { - case reflect.Ptr, reflect.Interface, reflect.Invalid: - - if ct == nil { - return - } - - if ct.typeof == typeOmitEmpty || ct.typeof == typeIsDefault { - return - } - - if ct.hasTag { - if kind == reflect.Invalid { - v.str1 = string(append(ns, cf.altName...)) - if v.v.hasTagNameFunc { - v.str2 = string(append(structNs, cf.name...)) - } else { - v.str2 = v.str1 - } - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: ct.aliasTag, - actualTag: ct.tag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(cf.altName)), - structfieldLen: uint8(len(cf.name)), - param: ct.param, - kind: kind, - }, - ) - return - } - - v.str1 = string(append(ns, cf.altName...)) - if v.v.hasTagNameFunc { - v.str2 = string(append(structNs, cf.name...)) - } else { - v.str2 = v.str1 - } - if !ct.runValidationWhenNil { - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: ct.aliasTag, - actualTag: ct.tag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(cf.altName)), - structfieldLen: uint8(len(cf.name)), - value: current.Interface(), - param: ct.param, - kind: kind, - typ: current.Type(), - }, - ) - return - } - } - - case reflect.Struct: - - typ = current.Type() - - if typ != timeType { - - if ct != nil { - - if ct.typeof == typeStructOnly { - goto CONTINUE - } else if ct.typeof == typeIsDefault { - // set Field Level fields - v.slflParent = parent - v.flField = current - v.cf = cf - v.ct = ct - - if !ct.fn(ctx, v) { - v.str1 = string(append(ns, cf.altName...)) - - if v.v.hasTagNameFunc { - v.str2 = string(append(structNs, cf.name...)) - } else { - v.str2 = v.str1 - } - - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: ct.aliasTag, - actualTag: ct.tag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(cf.altName)), - structfieldLen: uint8(len(cf.name)), - value: current.Interface(), - param: ct.param, - kind: kind, - typ: typ, - }, - ) - return - } - } - - ct = ct.next - } - - if ct != nil && ct.typeof == typeNoStructLevel { - return - } - - CONTINUE: - // if len == 0 then validating using 'Var' or 'VarWithValue' - // Var - doesn't make much sense to do it that way, should call 'Struct', but no harm... - // VarWithField - this allows for validating against each field within the struct against a specific value - // pretty handy in certain situations - if len(cf.name) > 0 { - ns = append(append(ns, cf.altName...), '.') - structNs = append(append(structNs, cf.name...), '.') - } - - v.validateStruct(ctx, current, current, typ, ns, structNs, ct) - return - } - } - - if !ct.hasTag { - return - } - - typ = current.Type() - -OUTER: - for { - if ct == nil { - return - } - - switch ct.typeof { - - case typeOmitEmpty: - - // set Field Level fields - v.slflParent = parent - v.flField = current - v.cf = cf - v.ct = ct - - if !hasValue(v) { - return - } - - ct = ct.next - continue - - case typeEndKeys: - return - - case typeDive: - - ct = ct.next - - // traverse slice or map here - // or panic ;) - switch kind { - case reflect.Slice, reflect.Array: - - var i64 int64 - reusableCF := &cField{} - - for i := 0; i < current.Len(); i++ { - - i64 = int64(i) - - v.misc = append(v.misc[0:0], cf.name...) - v.misc = append(v.misc, '[') - v.misc = strconv.AppendInt(v.misc, i64, 10) - v.misc = append(v.misc, ']') - - reusableCF.name = string(v.misc) - - if cf.namesEqual { - reusableCF.altName = reusableCF.name - } else { - - v.misc = append(v.misc[0:0], cf.altName...) - v.misc = append(v.misc, '[') - v.misc = strconv.AppendInt(v.misc, i64, 10) - v.misc = append(v.misc, ']') - - reusableCF.altName = string(v.misc) - } - v.traverseField(ctx, parent, current.Index(i), ns, structNs, reusableCF, ct) - } - - case reflect.Map: - - var pv string - reusableCF := &cField{} - - for _, key := range current.MapKeys() { - - pv = fmt.Sprintf("%v", key.Interface()) - - v.misc = append(v.misc[0:0], cf.name...) - v.misc = append(v.misc, '[') - v.misc = append(v.misc, pv...) - v.misc = append(v.misc, ']') - - reusableCF.name = string(v.misc) - - if cf.namesEqual { - reusableCF.altName = reusableCF.name - } else { - v.misc = append(v.misc[0:0], cf.altName...) - v.misc = append(v.misc, '[') - v.misc = append(v.misc, pv...) - v.misc = append(v.misc, ']') - - reusableCF.altName = string(v.misc) - } - - if ct != nil && ct.typeof == typeKeys && ct.keys != nil { - v.traverseField(ctx, parent, key, ns, structNs, reusableCF, ct.keys) - // can be nil when just keys being validated - if ct.next != nil { - v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct.next) - } - } else { - v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct) - } - } - - default: - // throw error, if not a slice or map then should not have gotten here - // bad dive tag - panic("dive error! can't dive on a non slice or map") - } - - return - - case typeOr: - - v.misc = v.misc[0:0] - - for { - - // set Field Level fields - v.slflParent = parent - v.flField = current - v.cf = cf - v.ct = ct - - if ct.fn(ctx, v) { - - // drain rest of the 'or' values, then continue or leave - for { - - ct = ct.next - - if ct == nil { - return - } - - if ct.typeof != typeOr { - continue OUTER - } - } - } - - v.misc = append(v.misc, '|') - v.misc = append(v.misc, ct.tag...) - - if ct.hasParam { - v.misc = append(v.misc, '=') - v.misc = append(v.misc, ct.param...) - } - - if ct.isBlockEnd || ct.next == nil { - // if we get here, no valid 'or' value and no more tags - v.str1 = string(append(ns, cf.altName...)) - - if v.v.hasTagNameFunc { - v.str2 = string(append(structNs, cf.name...)) - } else { - v.str2 = v.str1 - } - - if ct.hasAlias { - - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: ct.aliasTag, - actualTag: ct.actualAliasTag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(cf.altName)), - structfieldLen: uint8(len(cf.name)), - value: current.Interface(), - param: ct.param, - kind: kind, - typ: typ, - }, - ) - - } else { - - tVal := string(v.misc)[1:] - - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: tVal, - actualTag: tVal, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(cf.altName)), - structfieldLen: uint8(len(cf.name)), - value: current.Interface(), - param: ct.param, - kind: kind, - typ: typ, - }, - ) - } - - return - } - - ct = ct.next - } - - default: - - // set Field Level fields - v.slflParent = parent - v.flField = current - v.cf = cf - v.ct = ct - - if !ct.fn(ctx, v) { // 这是 验证函数的进行校验, 不成功就会记录下来 - - v.str1 = string(append(ns, cf.altName...)) //如果不想要 命名空间,就不要拼接 ns - - if v.v.hasTagNameFunc { - v.str2 = string(append(structNs, cf.name...)) - } else { - v.str2 = v.str1 - } - - v.errs = append(v.errs, - &fieldError{ - v: v.v, - tag: ct.aliasTag, - actualTag: ct.tag, - ns: v.str1, - structNs: v.str2, - fieldLen: uint8(len(cf.altName)), - structfieldLen: uint8(len(cf.name)), - value: current.Interface(), - param: ct.param, - kind: kind, - typ: typ, - }, - ) - - return - } - ct = ct.next - } - } - -} diff --git a/go-playground/validator/v10/validator_instance.go b/go-playground/validator/v10/validator_instance.go deleted file mode 100644 index bbe7a4f..0000000 --- a/go-playground/validator/v10/validator_instance.go +++ /dev/null @@ -1,619 +0,0 @@ -package validator - -import ( - "context" - "errors" - "fmt" - "reflect" - "strings" - "sync" - "time" - - ut "git.ningdatech.com/ningda/gin_valid/go-playground/universal-translator" -) - -const ( - defaultTagName = "validate" - utf8HexComma = "0x2C" - utf8Pipe = "0x7C" - tagSeparator = "," // tag参数 的分离符号, - orSeparator = "|" // 或者 的分离符号 - tagKeySeparator = "=" - structOnlyTag = "structonly" - noStructLevelTag = "nostructlevel" - omitempty = "omitempty" - isdefault = "isdefault" - requiredWithoutAllTag = "required_without_all" - requiredWithoutTag = "required_without" - requiredWithTag = "required_with" - requiredWithAllTag = "required_with_all" - requiredIfTag = "required_if" - requiredUnlessTag = "required_unless" - skipValidationTag = "-" - diveTag = "dive" - keysTag = "keys" - endKeysTag = "endkeys" - requiredTag = "required" - namespaceSeparator = "." - leftBracket = "[" - rightBracket = "]" - restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}" - restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" - restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" -) - -var ( - timeDurationType = reflect.TypeOf(time.Duration(0)) - timeType = reflect.TypeOf(time.Time{}) - - defaultCField = &cField{namesEqual: true} -) - -// FilterFunc is the type used to filter fields using -// StructFiltered(...) function. -// returning true results in the field being filtered/skiped from -// validation -type FilterFunc func(ns []byte) bool - -// CustomTypeFunc allows for overriding or adding custom field type handler functions -// field = field value of the type to return a value to be validated -// example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29 -type CustomTypeFunc func(field reflect.Value) interface{} - -// TagNameFunc allows for adding of a custom tag name parser -type TagNameFunc func(field reflect.StructField) string - -type internalValidationFuncWrapper struct { - fn FuncCtx - runValidatinOnNil bool -} - -// Validate contains the validator settings and cache -type Validate struct { - tagName string - pool *sync.Pool - hasCustomFuncs bool - hasTagNameFunc bool - tagNameFunc TagNameFunc - structLevelFuncs map[reflect.Type]StructLevelFuncCtx - customFuncs map[reflect.Type]CustomTypeFunc - aliases map[string]string - validations map[string]internalValidationFuncWrapper // 每个 tag如 gte 都会对应一个func处理, 如果这个tag没有函数处理会报错 - transTagFunc map[ut.Translator]map[string]TranslationFunc // map[]map[]TranslationFunc - tagCache *tagCache - structCache *structCache -} - -// New returns a new instance of 'validate' with sane defaults. -func New() *Validate { - - tc := new(tagCache) - tc.m.Store(make(map[string]*cTag)) - - sc := new(structCache) - sc.m.Store(make(map[reflect.Type]*cStruct)) - - v := &Validate{ - tagName: defaultTagName, - aliases: make(map[string]string, len(bakedInAliases)), - validations: make(map[string]internalValidationFuncWrapper, len(bakedInValidators)), - tagCache: tc, - structCache: sc, - } - - // must copy alias validators for separate validations to be used in each validator instance - for k, val := range bakedInAliases { - v.RegisterAlias(k, val) - } - - // must copy validators for separate validations to be used in each instance - for k, val := range bakedInValidators { - - switch k { - // these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour - case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag: - _ = v.registerValidation(k, wrapFunc(val), true, true) - default: - // no need to error check here, baked in will always be valid - _ = v.registerValidation(k, wrapFunc(val), true, false) - } - } - - v.pool = &sync.Pool{ - New: func() interface{} { - return &validate{ - v: v, - ns: make([]byte, 0, 64), - actualNs: make([]byte, 0, 64), - misc: make([]byte, 32), - } - }, - } - - return v -} - -// SetTagName allows for changing of the default tag name of 'validate' -func (v *Validate) SetTagName(name string) { - v.tagName = name -} - -// RegisterTagNameFunc registers a function to get alternate names for StructFields. -// -// eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names: -// -// validate.RegisterTagNameFunc(func(fld reflect.StructField) string { -// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] -// if name == "-" { -// return "" -// } -// return name -// }) -func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) { - v.tagNameFunc = fn - v.hasTagNameFunc = true -} - -// RegisterValidation adds a validation with the given tag -// -// NOTES: -// - if the key already exists, the previous validation function will be replaced. -// - this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterValidation(tag string, fn Func, callValidationEvenIfNull ...bool) error { - return v.RegisterValidationCtx(tag, wrapFunc(fn), callValidationEvenIfNull...) -} - -// RegisterValidationCtx does the same as RegisterValidation on accepts a FuncCtx validation -// allowing context.Context validation support. -func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationEvenIfNull ...bool) error { - var nilCheckable bool - if len(callValidationEvenIfNull) > 0 { - nilCheckable = callValidationEvenIfNull[0] - } - return v.registerValidation(tag, fn, false, nilCheckable) -} - -func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error { - if len(tag) == 0 { - return errors.New("Function Key cannot be empty") - } - - if fn == nil { - return errors.New("Function cannot be empty") - } - - _, ok := restrictedTags[tag] - if !bakedIn && (ok || strings.ContainsAny(tag, restrictedTagChars)) { - panic(fmt.Sprintf(restrictedTagErr, tag)) - } - v.validations[tag] = internalValidationFuncWrapper{fn: fn, runValidatinOnNil: nilCheckable} - return nil -} - -// RegisterAlias registers a mapping of a single validation tag that -// defines a common or complex set of validation(s) to simplify adding validation -// to structs. -// -// NOTE: this function is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterAlias(alias, tags string) { - - _, ok := restrictedTags[alias] - - if ok || strings.ContainsAny(alias, restrictedTagChars) { - panic(fmt.Sprintf(restrictedAliasErr, alias)) - } - - v.aliases[alias] = tags -} - -// RegisterStructValidation registers a StructLevelFunc against a number of types. -// -// NOTE: -// - this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) { - v.RegisterStructValidationCtx(wrapStructLevelFunc(fn), types...) -} - -// RegisterStructValidationCtx registers a StructLevelFuncCtx against a number of types and allows passing -// of contextual validation information via context.Context. -// -// NOTE: -// - this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...interface{}) { - - if v.structLevelFuncs == nil { - v.structLevelFuncs = make(map[reflect.Type]StructLevelFuncCtx) - } - - for _, t := range types { - tv := reflect.ValueOf(t) - if tv.Kind() == reflect.Ptr { - t = reflect.Indirect(tv).Interface() - } - - v.structLevelFuncs[reflect.TypeOf(t)] = fn - } -} - -// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types -// -// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation -func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) { - - if v.customFuncs == nil { - v.customFuncs = make(map[reflect.Type]CustomTypeFunc) - } - - for _, t := range types { - v.customFuncs[reflect.TypeOf(t)] = fn - } - - v.hasCustomFuncs = true -} - -// RegisterTranslation registers translations against the provided tag. -func (v *Validate) RegisterTranslation(tag string, trans ut.Translator, registerFn RegisterTranslationsFunc, translationFn TranslationFunc) (err error) { - - if v.transTagFunc == nil { - v.transTagFunc = make(map[ut.Translator]map[string]TranslationFunc) - } - - if err = registerFn(trans); err != nil { - return - } - - m, ok := v.transTagFunc[trans] - if !ok { - m = make(map[string]TranslationFunc) - v.transTagFunc[trans] = m - } - - m[tag] = translationFn - - return -} - -// Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified. -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) Struct(s interface{}) error { - return v.StructCtx(context.Background(), s) -} - -// StructCtx validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified -// and also allows passing of context.Context for contextual validation information. -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) { - - val := reflect.ValueOf(s) - top := val - - if val.Kind() == reflect.Ptr && !val.IsNil() { - val = val.Elem() - } - - if val.Kind() != reflect.Struct || val.Type() == timeType { - return &InvalidValidationError{Type: reflect.TypeOf(s)} - } - - // good to validate - vd := v.pool.Get().(*validate) - vd.top = top - vd.isPartial = false - // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept - - vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil) - - if len(vd.errs) > 0 { - err = vd.errs - vd.errs = nil - } - - v.pool.Put(vd) - - return -} - -// StructFiltered validates a structs exposed fields, that pass the FilterFunc check and automatically validates -// nested structs, unless otherwise specified. -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructFiltered(s interface{}, fn FilterFunc) error { - return v.StructFilteredCtx(context.Background(), s, fn) -} - -// StructFilteredCtx validates a structs exposed fields, that pass the FilterFunc check and automatically validates -// nested structs, unless otherwise specified and also allows passing of contextual validation information via -// context.Context -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{}, fn FilterFunc) (err error) { - val := reflect.ValueOf(s) - top := val - - if val.Kind() == reflect.Ptr && !val.IsNil() { - val = val.Elem() - } - - if val.Kind() != reflect.Struct || val.Type() == timeType { - return &InvalidValidationError{Type: reflect.TypeOf(s)} - } - - // good to validate - vd := v.pool.Get().(*validate) - vd.top = top - vd.isPartial = true - vd.ffn = fn - // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept - - vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil) - - if len(vd.errs) > 0 { - err = vd.errs - vd.errs = nil - } - - v.pool.Put(vd) - - return -} - -// StructPartial validates the fields passed in only, ignoring all others. -// Fields may be provided in a namespaced fashion relative to the struct provided -// eg. NestedStruct.Field or NestedArrayField[0].Struct.Name -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructPartial(s interface{}, fields ...string) error { - return v.StructPartialCtx(context.Background(), s, fields...) -} - -// StructPartialCtx validates the fields passed in only, ignoring all others and allows passing of contextual -// validation validation information via context.Context -// Fields may be provided in a namespaced fashion relative to the struct provided -// eg. NestedStruct.Field or NestedArrayField[0].Struct.Name -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields ...string) (err error) { - val := reflect.ValueOf(s) - top := val - - if val.Kind() == reflect.Ptr && !val.IsNil() { - val = val.Elem() - } - - if val.Kind() != reflect.Struct || val.Type() == timeType { - return &InvalidValidationError{Type: reflect.TypeOf(s)} - } - - // good to validate - vd := v.pool.Get().(*validate) - vd.top = top - vd.isPartial = true - vd.ffn = nil - vd.hasExcludes = false - vd.includeExclude = make(map[string]struct{}) - - typ := val.Type() - name := typ.Name() - - for _, k := range fields { - - flds := strings.Split(k, namespaceSeparator) - if len(flds) > 0 { - - vd.misc = append(vd.misc[0:0], name...) - vd.misc = append(vd.misc, '.') - - for _, s := range flds { - - idx := strings.Index(s, leftBracket) - - if idx != -1 { - for idx != -1 { - vd.misc = append(vd.misc, s[:idx]...) - vd.includeExclude[string(vd.misc)] = struct{}{} - - idx2 := strings.Index(s, rightBracket) - idx2++ - vd.misc = append(vd.misc, s[idx:idx2]...) - vd.includeExclude[string(vd.misc)] = struct{}{} - s = s[idx2:] - idx = strings.Index(s, leftBracket) - } - } else { - - vd.misc = append(vd.misc, s...) - vd.includeExclude[string(vd.misc)] = struct{}{} - } - - vd.misc = append(vd.misc, '.') - } - } - } - - vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) - - if len(vd.errs) > 0 { - err = vd.errs - vd.errs = nil - } - - v.pool.Put(vd) - - return -} - -// StructExcept validates all fields except the ones passed in. -// Fields may be provided in a namespaced fashion relative to the struct provided -// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructExcept(s interface{}, fields ...string) error { - return v.StructExceptCtx(context.Background(), s, fields...) -} - -// StructExceptCtx validates all fields except the ones passed in and allows passing of contextual -// validation validation information via context.Context -// Fields may be provided in a namespaced fashion relative to the struct provided -// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ...string) (err error) { - val := reflect.ValueOf(s) - top := val - - if val.Kind() == reflect.Ptr && !val.IsNil() { - val = val.Elem() - } - - if val.Kind() != reflect.Struct || val.Type() == timeType { - return &InvalidValidationError{Type: reflect.TypeOf(s)} - } - - // good to validate - vd := v.pool.Get().(*validate) - vd.top = top - vd.isPartial = true - vd.ffn = nil - vd.hasExcludes = true - vd.includeExclude = make(map[string]struct{}) - - typ := val.Type() - name := typ.Name() - - for _, key := range fields { - - vd.misc = vd.misc[0:0] - - if len(name) > 0 { - vd.misc = append(vd.misc, name...) - vd.misc = append(vd.misc, '.') - } - - vd.misc = append(vd.misc, key...) - vd.includeExclude[string(vd.misc)] = struct{}{} - } - - vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil) - - if len(vd.errs) > 0 { - err = vd.errs - vd.errs = nil - } - - v.pool.Put(vd) - - return -} - -// Var validates a single variable using tag style validation. -// eg. -// var i int -// validate.Var(i, "gt=1,lt=10") -// -// WARNING: a struct can be passed for validation eg. time.Time is a struct or -// if you have a custom type and have registered a custom type handler, so must -// allow it; however unforeseen validations will occur if trying to validate a -// struct that is meant to be passed to 'validate.Struct' -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -// validate Array, Slice and maps fields which may contain more than one error -func (v *Validate) Var(field interface{}, tag string) error { - return v.VarCtx(context.Background(), field, tag) -} - -// VarCtx validates a single variable using tag style validation and allows passing of contextual -// validation validation information via context.Context. -// eg. -// var i int -// validate.Var(i, "gt=1,lt=10") -// -// WARNING: a struct can be passed for validation eg. time.Time is a struct or -// if you have a custom type and have registered a custom type handler, so must -// allow it; however unforeseen validations will occur if trying to validate a -// struct that is meant to be passed to 'validate.Struct' -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -// validate Array, Slice and maps fields which may contain more than one error -func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (err error) { - if len(tag) == 0 || tag == skipValidationTag { - return nil - } - - ctag := v.fetchCacheTag(tag) - val := reflect.ValueOf(field) - vd := v.pool.Get().(*validate) - vd.top = val - vd.isPartial = false - vd.traverseField(ctx, val, val, vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) - - if len(vd.errs) > 0 { - err = vd.errs - vd.errs = nil - } - v.pool.Put(vd) - return -} - -// VarWithValue validates a single variable, against another variable/field's value using tag style validation -// eg. -// s1 := "abcd" -// s2 := "abcd" -// validate.VarWithValue(s1, s2, "eqcsfield") // returns true -// -// WARNING: a struct can be passed for validation eg. time.Time is a struct or -// if you have a custom type and have registered a custom type handler, so must -// allow it; however unforeseen validations will occur if trying to validate a -// struct that is meant to be passed to 'validate.Struct' -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -// validate Array, Slice and maps fields which may contain more than one error -func (v *Validate) VarWithValue(field interface{}, other interface{}, tag string) error { - return v.VarWithValueCtx(context.Background(), field, other, tag) -} - -// VarWithValueCtx validates a single variable, against another variable/field's value using tag style validation and -// allows passing of contextual validation validation information via context.Context. -// eg. -// s1 := "abcd" -// s2 := "abcd" -// validate.VarWithValue(s1, s2, "eqcsfield") // returns true -// -// WARNING: a struct can be passed for validation eg. time.Time is a struct or -// if you have a custom type and have registered a custom type handler, so must -// allow it; however unforeseen validations will occur if trying to validate a -// struct that is meant to be passed to 'validate.Struct' -// -// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. -// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. -// validate Array, Slice and maps fields which may contain more than one error -func (v *Validate) VarWithValueCtx(ctx context.Context, field interface{}, other interface{}, tag string) (err error) { - if len(tag) == 0 || tag == skipValidationTag { - return nil - } - ctag := v.fetchCacheTag(tag) - otherVal := reflect.ValueOf(other) - vd := v.pool.Get().(*validate) - vd.top = otherVal - vd.isPartial = false - vd.traverseField(ctx, otherVal, reflect.ValueOf(field), vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) - - if len(vd.errs) > 0 { - err = vd.errs - vd.errs = nil - } - v.pool.Put(vd) - return -} diff --git a/go.mod b/go.mod deleted file mode 100644 index b51d074..0000000 --- a/go.mod +++ /dev/null @@ -1,13 +0,0 @@ -module git.ningdatech.com/ningda/gin_valid - -go 1.13 - -require ( - github.com/golang/protobuf v1.4.3 - github.com/json-iterator/go v1.1.10 // indirect - github.com/leodido/go-urn v1.2.0 - github.com/ugorji/go v1.2.0 // indirect - github.com/ugorji/go/codec v1.2.0 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 - gopkg.in/yaml.v2 v2.4.0 -) diff --git a/main.go b/main.go deleted file mode 100644 index e0b87a2..0000000 --- a/main.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func main() { - return -}