增加websocket支持

This commit is contained in:
2025-09-08 13:47:13 +08:00
parent 9caedd697d
commit 7e0fd53dd3
336 changed files with 9020 additions and 20356 deletions

View File

@@ -1,4 +1,4 @@
GOCMD=go
GOCMD=GO111MODULE=on go
linters-install:
@golangci-lint --version >/dev/null 2>&1 || { \
@@ -13,6 +13,6 @@ test:
$(GOCMD) test -cover -race ./...
bench:
$(GOCMD) test -run=NONE -bench=. -benchmem ./...
$(GOCMD) test -bench=. -benchmem ./...
.PHONY: test lint linters-install
.PHONY: test lint linters-install

View File

@@ -1,7 +1,7 @@
Package validator
=================
<img align="right" src="logo.png">[![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.20.0-green.svg)
<img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v10/logo.png">[![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.14.0-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)
@@ -67,12 +67,6 @@ Please see https://pkg.go.dev/github.com/go-playground/validator/v10 for detaile
Baked-in Validations
------
### Special Notes:
- If new to using validator it is highly recommended to initialize it using the `WithRequiredStructEnabled` option which is opt-in to new behaviour that will become the default behaviour in v11+. See documentation for more details.
```go
validate := validator.New(validator.WithRequiredStructEnabled())
```
### Fields:
| Tag | Description |
@@ -164,7 +158,6 @@ validate := validator.New(validator.WithRequiredStructEnabled())
| credit_card | Credit Card Number |
| mongodb | MongoDB ObjectID |
| cron | Cron |
| spicedb | SpiceDb ObjectID/Permission/Type |
| datetime | Datetime |
| e164 | e164 formatted phone number |
| email | E-mail String
@@ -178,7 +171,6 @@ validate := validator.New(validator.WithRequiredStructEnabled())
| isbn | International Standard Book Number |
| isbn10 | International Standard Book Number 10 |
| isbn13 | International Standard Book Number 13 |
| issn | International Standard Serial Number |
| iso3166_1_alpha2 | Two-letter country code (ISO 3166-1 alpha-2) |
| iso3166_1_alpha3 | Three-letter country code (ISO 3166-1 alpha-3) |
| iso3166_1_alpha_numeric | Numeric country code (ISO 3166-1 numeric) |
@@ -267,72 +259,71 @@ Benchmarks
------
###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64
```go
go version go1.21.0 darwin/arm64
goos: darwin
goarch: arm64
pkg: github.com/go-playground/validator/v10
BenchmarkFieldSuccess-8 33142266 35.94 ns/op 0 B/op 0 allocs/op
BenchmarkFieldSuccessParallel-8 200816191 6.568 ns/op 0 B/op 0 allocs/op
BenchmarkFieldFailure-8 6779707 175.1 ns/op 200 B/op 4 allocs/op
BenchmarkFieldFailureParallel-8 11044147 108.4 ns/op 200 B/op 4 allocs/op
BenchmarkFieldArrayDiveSuccess-8 6054232 194.4 ns/op 97 B/op 5 allocs/op
BenchmarkFieldArrayDiveSuccessParallel-8 12523388 94.07 ns/op 97 B/op 5 allocs/op
BenchmarkFieldArrayDiveFailure-8 3587043 334.3 ns/op 300 B/op 10 allocs/op
BenchmarkFieldArrayDiveFailureParallel-8 5816665 200.8 ns/op 300 B/op 10 allocs/op
BenchmarkFieldMapDiveSuccess-8 2217910 540.1 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveSuccessParallel-8 4446698 258.7 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveFailure-8 2392759 504.6 ns/op 376 B/op 13 allocs/op
BenchmarkFieldMapDiveFailureParallel-8 4244199 286.9 ns/op 376 B/op 13 allocs/op
BenchmarkFieldMapDiveWithKeysSuccess-8 2005857 592.1 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveWithKeysSuccessParallel-8 4400850 296.9 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveWithKeysFailure-8 1850227 643.8 ns/op 553 B/op 16 allocs/op
BenchmarkFieldMapDiveWithKeysFailureParallel-8 3293233 375.1 ns/op 553 B/op 16 allocs/op
BenchmarkFieldCustomTypeSuccess-8 12174412 98.25 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-8 34389907 35.49 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeFailure-8 7582524 156.6 ns/op 184 B/op 3 allocs/op
BenchmarkFieldCustomTypeFailureParallel-8 13019902 92.79 ns/op 184 B/op 3 allocs/op
BenchmarkFieldOrTagSuccess-8 3427260 349.4 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagSuccessParallel-8 15144128 81.25 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagFailure-8 5913546 201.9 ns/op 216 B/op 5 allocs/op
BenchmarkFieldOrTagFailureParallel-8 9810212 113.7 ns/op 216 B/op 5 allocs/op
BenchmarkStructLevelValidationSuccess-8 13456327 87.66 ns/op 16 B/op 1 allocs/op
BenchmarkStructLevelValidationSuccessParallel-8 41818888 27.77 ns/op 16 B/op 1 allocs/op
BenchmarkStructLevelValidationFailure-8 4166284 272.6 ns/op 264 B/op 7 allocs/op
BenchmarkStructLevelValidationFailureParallel-8 7594581 152.1 ns/op 264 B/op 7 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-8 6508082 182.6 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-8 23078605 54.78 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-8 3118352 381.0 ns/op 416 B/op 9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-8 5300738 224.1 ns/op 432 B/op 10 allocs/op
BenchmarkStructFilteredSuccess-8 4761807 251.1 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredSuccessParallel-8 8792598 128.6 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredFailure-8 5202573 232.1 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredFailureParallel-8 9591267 121.4 ns/op 216 B/op 5 allocs/op
BenchmarkStructPartialSuccess-8 5188512 231.6 ns/op 224 B/op 4 allocs/op
BenchmarkStructPartialSuccessParallel-8 9179776 123.1 ns/op 224 B/op 4 allocs/op
BenchmarkStructPartialFailure-8 3071212 392.5 ns/op 440 B/op 9 allocs/op
BenchmarkStructPartialFailureParallel-8 5344261 223.7 ns/op 440 B/op 9 allocs/op
BenchmarkStructExceptSuccess-8 3184230 375.0 ns/op 424 B/op 8 allocs/op
BenchmarkStructExceptSuccessParallel-8 10090130 108.9 ns/op 208 B/op 3 allocs/op
BenchmarkStructExceptFailure-8 3347226 357.7 ns/op 424 B/op 8 allocs/op
BenchmarkStructExceptFailureParallel-8 5654923 209.5 ns/op 424 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-8 5232265 229.1 ns/op 56 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-8 17436674 64.75 ns/op 56 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-8 3128613 383.6 ns/op 272 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-8 6994113 168.8 ns/op 272 B/op 8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3506487 340.9 ns/op 64 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 13431300 91.77 ns/op 64 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2410566 500.9 ns/op 288 B/op 9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 6344510 188.2 ns/op 288 B/op 9 allocs/op
BenchmarkStructSimpleSuccess-8 8922726 133.8 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleSuccessParallel-8 55291153 23.63 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleFailure-8 3171553 378.4 ns/op 416 B/op 9 allocs/op
BenchmarkStructSimpleFailureParallel-8 5571692 212.0 ns/op 416 B/op 9 allocs/op
BenchmarkStructComplexSuccess-8 1683750 714.5 ns/op 224 B/op 5 allocs/op
BenchmarkStructComplexSuccessParallel-8 4578046 257.0 ns/op 224 B/op 5 allocs/op
BenchmarkStructComplexFailure-8 481585 2547 ns/op 3041 B/op 48 allocs/op
BenchmarkStructComplexFailureParallel-8 965764 1577 ns/op 3040 B/op 48 allocs/op
BenchmarkOneof-8 17380881 68.50 ns/op 0 B/op 0 allocs/op
BenchmarkOneofParallel-8 8084733 153.5 ns/op 0 B/op 0 allocs/op
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

View File

@@ -23,7 +23,7 @@ import (
"golang.org/x/text/language"
"github.com/gabriel-vasile/mimetype"
urn "github.com/leodido/go-urn"
"github.com/leodido/go-urn"
)
// Func accepts a FieldLevel interface for all validation needs. The return
@@ -51,7 +51,6 @@ var (
endKeysTag: {},
structOnlyTag: {},
omitempty: {},
omitnil: {},
skipValidationTag: {},
utf8HexComma: {},
utf8Pipe: {},
@@ -64,9 +63,8 @@ var (
// 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",
"eu_country_code": "iso3166_1_alpha2_eu|iso3166_1_alpha3_eu|iso3166_1_alpha_numeric_eu",
"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
@@ -134,7 +132,6 @@ var (
"urn_rfc2141": isUrnRFC2141, // RFC 2141
"file": isFile,
"filepath": isFilePath,
"base32": isBase32,
"base64": isBase64,
"base64url": isBase64URL,
"base64rawurl": isBase64RawURL,
@@ -152,7 +149,6 @@ var (
"isbn": isISBN,
"isbn10": isISBN10,
"isbn13": isISBN13,
"issn": isISSN,
"eth_addr": isEthereumAddress,
"eth_addr_checksum": isEthereumAddressChecksum,
"btc_addr": isBitcoinAddress,
@@ -218,11 +214,8 @@ var (
"datetime": isDatetime,
"timezone": isTimeZone,
"iso3166_1_alpha2": isIso3166Alpha2,
"iso3166_1_alpha2_eu": isIso3166Alpha2EU,
"iso3166_1_alpha3": isIso3166Alpha3,
"iso3166_1_alpha3_eu": isIso3166Alpha3EU,
"iso3166_1_alpha_numeric": isIso3166AlphaNumeric,
"iso3166_1_alpha_numeric_eu": isIso3166AlphaNumericEU,
"iso3166_2": isIso31662,
"iso4217": isIso4217,
"iso4217_numeric": isIso4217Numeric,
@@ -237,7 +230,6 @@ var (
"luhn_checksum": hasLuhnChecksum,
"mongodb": isMongoDB,
"cron": isCron,
"spicedb": isSpiceDB,
}
)
@@ -380,9 +372,9 @@ func isMAC(fl FieldLevel) bool {
// isCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
func isCIDRv4(fl FieldLevel) bool {
ip, net, err := net.ParseCIDR(fl.Field().String())
ip, _, err := net.ParseCIDR(fl.Field().String())
return err == nil && ip.To4() != nil && net.IP.Equal(ip)
return err == nil && ip.To4() != nil
}
// isCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address.
@@ -515,47 +507,47 @@ func isASCII(fl FieldLevel) bool {
// isUUID5 is the validation function for validating if the field's value is a valid v5 UUID.
func isUUID5(fl FieldLevel) bool {
return fieldMatchesRegexByStringerValOrString(uUID5Regex, fl)
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 fieldMatchesRegexByStringerValOrString(uUID4Regex, fl)
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 fieldMatchesRegexByStringerValOrString(uUID3Regex, fl)
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 fieldMatchesRegexByStringerValOrString(uUIDRegex, fl)
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 fieldMatchesRegexByStringerValOrString(uUID5RFC4122Regex, fl)
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 fieldMatchesRegexByStringerValOrString(uUID4RFC4122Regex, fl)
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 fieldMatchesRegexByStringerValOrString(uUID3RFC4122Regex, fl)
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 fieldMatchesRegexByStringerValOrString(uUIDRFC4122Regex, fl)
return uUIDRFC4122Regex.MatchString(fl.Field().String())
}
// isULID is the validation function for validating if the field's value is a valid ULID.
func isULID(fl FieldLevel) bool {
return fieldMatchesRegexByStringerValOrString(uLIDRegex, fl)
return uLIDRegex.MatchString(fl.Field().String())
}
// isMD4 is the validation function for validating if the field's value is a valid MD4.
@@ -657,32 +649,6 @@ func isISBN10(fl FieldLevel) bool {
return checksum%11 == 0
}
// isISSN is the validation function for validating if the field's value is a valid ISSN.
func isISSN(fl FieldLevel) bool {
s := fl.Field().String()
if !iSSNRegex.MatchString(s) {
return false
}
s = strings.ReplaceAll(s, "-", "")
pos := 8
checksum := 0
for i := 0; i < 7; i++ {
checksum += pos * int(s[i]-'0')
pos--
}
if s[7] == 'X' {
checksum += 10
} else {
checksum += int(s[7] - '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()
@@ -1328,13 +1294,8 @@ func isEq(fl FieldLevel) bool {
return field.Uint() == p
case reflect.Float32:
p := asFloat32(param)
return field.Float() == p
case reflect.Float64:
p := asFloat64(param)
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return field.Float() == p
@@ -1404,11 +1365,6 @@ func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool {
return reg.MatchString(field.String())
}
// isBase32 is the validation function for validating if the current field's value is a valid base 32.
func isBase32(fl FieldLevel) bool {
return base32Regex.MatchString(fl.Field().String())
}
// 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())
@@ -1451,15 +1407,6 @@ func isURI(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
// isFileURL is the helper function for validating if the `path` valid file URL as per RFC8089
func isFileURL(path string) bool {
if !strings.HasPrefix(path, "file:/") {
return false
}
_, err := url.ParseRequestURI(path)
return err == nil
}
// 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()
@@ -1467,25 +1414,25 @@ func isURL(fl FieldLevel) bool {
switch field.Kind() {
case reflect.String:
s := strings.ToLower(field.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
}
if isFileURL(s) {
return true
}
url, err := url.ParseRequestURI(s)
url, err := url.Parse(s)
if err != nil || url.Scheme == "" {
return false
}
if url.Host == "" && url.Fragment == "" && url.Opaque == "" {
return false
}
return true
}
@@ -1503,13 +1450,7 @@ func isHttpURL(fl FieldLevel) bool {
case reflect.String:
s := strings.ToLower(field.String())
url, err := url.Parse(s)
if err != nil || url.Host == "" {
return false
}
return url.Scheme == "http" || url.Scheme == "https"
return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://")
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
@@ -1618,10 +1559,6 @@ func isFilePath(fl FieldLevel) bool {
field := fl.Field()
// Not valid if it is a directory.
if isDir(fl) {
return false
}
// If it exists, it obviously is valid.
// This is done first to avoid code duplication and unnecessary additional logic.
if exists = isFile(fl); exists {
@@ -1771,7 +1708,7 @@ func hasValue(fl FieldLevel) bool {
if fl.(*validate).fldIsPointer && field.Interface() != nil {
return true
}
return field.IsValid() && !field.IsZero()
return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface()
}
}
@@ -1795,7 +1732,7 @@ func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue boo
if nullable && field.Interface() != nil {
return false
}
return field.IsValid() && field.IsZero()
return field.IsValid() && field.Interface() == reflect.Zero(field.Type()).Interface()
}
}
@@ -1816,11 +1753,8 @@ func requireCheckFieldValue(
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() == asUint(value)
case reflect.Float32:
return field.Float() == asFloat32(value)
case reflect.Float64:
return field.Float() == asFloat64(value)
case reflect.Float32, reflect.Float64:
return field.Float() == asFloat(value)
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) == asInt(value)
@@ -2119,13 +2053,8 @@ func isGte(fl FieldLevel) bool {
return field.Uint() >= p
case reflect.Float32:
p := asFloat32(param)
return field.Float() >= p
case reflect.Float64:
p := asFloat64(param)
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return field.Float() >= p
@@ -2170,16 +2099,10 @@ func isGt(fl FieldLevel) bool {
return field.Uint() > p
case reflect.Float32:
p := asFloat32(param)
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return field.Float() > p
case reflect.Float64:
p := asFloat64(param)
return field.Float() > p
case reflect.Struct:
if field.Type().ConvertibleTo(timeType) {
@@ -2218,13 +2141,8 @@ func hasLengthOf(fl FieldLevel) bool {
return field.Uint() == p
case reflect.Float32:
p := asFloat32(param)
return field.Float() == p
case reflect.Float64:
p := asFloat64(param)
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return field.Float() == p
}
@@ -2356,13 +2274,8 @@ func isLte(fl FieldLevel) bool {
return field.Uint() <= p
case reflect.Float32:
p := asFloat32(param)
return field.Float() <= p
case reflect.Float64:
p := asFloat64(param)
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return field.Float() <= p
@@ -2407,13 +2320,8 @@ func isLt(fl FieldLevel) bool {
return field.Uint() < p
case reflect.Float32:
p := asFloat32(param)
return field.Float() < p
case reflect.Float64:
p := asFloat64(param)
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return field.Float() < p
@@ -2660,17 +2568,9 @@ func isDirPath(fl FieldLevel) bool {
func isJSON(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.String:
if field.Kind() == reflect.String {
val := field.String()
return json.Valid([]byte(val))
case reflect.Slice:
fieldType := field.Type()
if fieldType.ConvertibleTo(byteSliceType) {
b := field.Convert(byteSliceType).Interface().([]byte)
return json.Valid(b)
}
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
@@ -2772,24 +2672,12 @@ func isIso3166Alpha2(fl FieldLevel) bool {
return iso3166_1_alpha2[val]
}
// isIso3166Alpha2EU is the validation function for validating if the current field's value is a valid iso3166-1 alpha-2 European Union country code.
func isIso3166Alpha2EU(fl FieldLevel) bool {
val := fl.Field().String()
return iso3166_1_alpha2_eu[val]
}
// isIso3166Alpha3 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]
}
// isIso3166Alpha3EU is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 European Union country code.
func isIso3166Alpha3EU(fl FieldLevel) bool {
val := fl.Field().String()
return iso3166_1_alpha3_eu[val]
}
// isIso3166AlphaNumeric 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()
@@ -2812,28 +2700,6 @@ func isIso3166AlphaNumeric(fl FieldLevel) bool {
return iso3166_1_alpha_numeric[code]
}
// isIso3166AlphaNumericEU is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric European Union country code.
func isIso3166AlphaNumericEU(fl FieldLevel) bool {
field := fl.Field()
var code int
switch field.Kind() {
case reflect.String:
i, err := strconv.Atoi(field.String())
if err != nil {
return false
}
code = i % 1000
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_eu[code]
}
// isIso31662 is the validation function for validating if the current field's value is a valid iso3166-2 code.
func isIso31662(fl FieldLevel) bool {
val := fl.Field().String()
@@ -2932,23 +2798,6 @@ func isMongoDB(fl FieldLevel) bool {
return mongodbRegex.MatchString(val)
}
// isSpiceDB is the validation function for validating if the current field's value is valid for use with Authzed SpiceDB in the indicated way
func isSpiceDB(fl FieldLevel) bool {
val := fl.Field().String()
param := fl.Param()
switch param {
case "permission":
return spicedbPermissionRegex.MatchString(val)
case "type":
return spicedbTypeRegex.MatchString(val)
case "id", "":
return spicedbIDRegex.MatchString(val)
}
panic("Unrecognized parameter: " + param)
}
// isCreditCard is the validation function for validating if the current field's value is a valid credit card number
func isCreditCard(fl FieldLevel) bool {
val := fl.Field().String()

View File

@@ -20,7 +20,6 @@ const (
typeOr
typeKeys
typeEndKeys
typeOmitNil
)
const (
@@ -126,7 +125,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
fld = typ.Field(i)
if !v.privateFieldValidation && !fld.Anonymous && len(fld.PkgPath) > 0 {
if !fld.Anonymous && len(fld.PkgPath) > 0 {
continue
}
@@ -253,10 +252,6 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s
current.typeof = typeOmitEmpty
continue
case omitnil:
current.typeof = typeOmitNil
continue
case structOnlyTag:
current.typeof = typeStructOnly
continue

View File

@@ -54,15 +54,6 @@ var iso3166_1_alpha2 = map[string]bool{
"EH": true, "YE": true, "ZM": true, "ZW": true, "XK": true,
}
var iso3166_1_alpha2_eu = map[string]bool{
"AT": true, "BE": true, "BG": true, "HR": true, "CY": true,
"CZ": true, "DK": true, "EE": true, "FI": true, "FR": true,
"DE": true, "GR": true, "HU": true, "IE": true, "IT": true,
"LV": true, "LT": true, "LU": true, "MT": true, "NL": true,
"PL": true, "PT": true, "RO": true, "SK": true, "SI": true,
"ES": true, "SE": 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,
@@ -116,15 +107,6 @@ var iso3166_1_alpha3 = map[string]bool{
"VNM": true, "VGB": true, "VIR": true, "WLF": true, "ESH": true,
"YEM": true, "ZMB": true, "ZWE": true, "ALA": true, "UNK": true,
}
var iso3166_1_alpha3_eu = map[string]bool{
"AUT": true, "BEL": true, "BGR": true, "HRV": true, "CYP": true,
"CZE": true, "DNK": true, "EST": true, "FIN": true, "FRA": true,
"DEU": true, "GRC": true, "HUN": true, "IRL": true, "ITA": true,
"LVA": true, "LTU": true, "LUX": true, "MLT": true, "NLD": true,
"POL": true, "PRT": true, "ROU": true, "SVK": true, "SVN": true,
"ESP": true, "SWE": 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,
@@ -179,15 +161,6 @@ var iso3166_1_alpha_numeric = map[int]bool{
887: true, 894: true, 716: true, 248: true, 153: true,
}
var iso3166_1_alpha_numeric_eu = map[int]bool{
40: true, 56: true, 100: true, 191: true, 196: true,
200: true, 208: true, 233: true, 246: true, 250: true,
276: true, 300: true, 348: true, 372: true, 380: true,
428: true, 440: true, 442: true, 470: true, 528: true,
616: true, 620: true, 642: true, 703: true, 705: true,
724: true, 752: true,
}
var iso3166_2 = map[string]bool{
"AD-02": true, "AD-03": true, "AD-04": true, "AD-05": true, "AD-06": true,
"AD-07": true, "AD-08": true, "AE-AJ": true, "AE-AZ": true, "AE-DU": true,

View File

@@ -194,13 +194,6 @@ such as min or max won't run, but if a value is set validation will run.
Usage: omitempty
# Omit Nil
Allows to skip the validation if the value is nil (same as omitempty, but
only for the nil-values).
Usage: omitnil
# Dive
This tells the validator to dive into a slice, array or map and validate that
@@ -254,7 +247,7 @@ Example #2
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. For structs ensures value is not the zero value when using WithRequiredStructEnabled.
ensures the value is not nil.
Usage: required
@@ -263,7 +256,7 @@ ensures the value is not nil. For structs ensures value is not the zero value wh
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. For structs ensures value is not the zero value.
interfaces, channels and functions ensures the value is not nil.
Usage: required_if
@@ -280,7 +273,7 @@ Examples:
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. For structs ensures value is not the zero value.
interfaces, channels and functions ensures the value is not nil.
Usage: required_unless
@@ -297,7 +290,7 @@ Examples:
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. For structs ensures value is not the zero value.
ensures the value is not nil.
Usage: required_with
@@ -314,7 +307,7 @@ Examples:
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. For structs ensures value is not the zero value.
ensures the value is not nil.
Usage: required_with_all
@@ -328,7 +321,7 @@ Example:
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. For structs ensures value is not the zero value.
ensures the value is not nil.
Usage: required_without
@@ -345,7 +338,7 @@ Examples:
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. For structs ensures value is not the zero value.
ensures the value is not nil.
Usage: required_without_all
@@ -359,7 +352,7 @@ Example:
The field under validation must not be present or 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. For structs ensures value is not the zero value.
interfaces, channels and functions ensures the value is not nil.
Usage: excluded_if
@@ -376,7 +369,7 @@ Examples:
The field under validation must not be present or 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. For structs ensures value is not the zero value.
interfaces, channels and functions ensures the value is not nil.
Usage: excluded_unless
@@ -886,6 +879,8 @@ This is done using os.Stat and github.com/gabriel-vasile/mimetype
Usage: image
# URL String
# File Path
This validates that a string value contains a valid file path but does not
@@ -916,15 +911,6 @@ according to the RFC 2141 spec.
Usage: urn_rfc2141
# Base32 String
This validates that a string value contains a valid bas324 value.
Although an empty string is valid base32 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: base32
# Base64 String
This validates that a string value contains a valid base64 value.
@@ -1398,12 +1384,6 @@ This validates that a string value contains a valid cron expression.
Usage: cron
# SpiceDb ObjectID/Permission/Object Type
This validates that a string is valid for use with SpiceDb for the indicated purpose. If no purpose is given, a purpose of 'id' is assumed.
Usage: spicedb=id|permission|type
# Alias Validators and Tags
Alias Validators and Tags

View File

@@ -257,19 +257,15 @@ func (fe *fieldError) Error() string {
// NOTE: if no registered translation can be found, it returns the original
// untranslated error message.
func (fe *fieldError) Translate(ut ut.Translator) string {
var fn TranslationFunc
m, ok := fe.v.transTagFunc[ut]
if !ok {
return fe.Error()
}
fn, ok = m[fe.tag]
fn, ok := m[fe.tag]
if !ok {
fn, ok = m[fe.actualTag]
if !ok {
return fe.Error()
}
return fe.Error()
}
return fn(ut, fe)

View File

@@ -17,13 +17,11 @@ const (
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}$"
base32RegexString = "^(?:[A-Z2-7]{8})*(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}=|[A-Z2-7]{8})$"
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})$"
base64RawURLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2,4})$"
iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$"
iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$"
iSSNRegexString = "^(?:[0-9]{4}-[0-9]{3}[0-9X])$"
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}$"
@@ -32,7 +30,7 @@ const (
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}$"
uLIDRegexString = "^(?i)[A-HJKMNP-TV-Z0-9]{26}$"
uLIDRegexString = "^[A-HJKMNP-TV-Z0-9]{26}$"
md4RegexString = "^[0-9a-f]{32}$"
md5RegexString = "^[0-9a-f]{32}$"
sha256RegexString = "^[0-9a-f]{64}$"
@@ -70,9 +68,6 @@ const (
cveRegexString = `^CVE-(1999|2\d{3})-(0[^0]\d{2}|0\d[^0]\d{1}|0\d{2}[^0]|[1-9]{1}\d{3,})$` // CVE Format Id https://cve.mitre.org/cve/identifiers/syntaxchange.html
mongodbRegexString = "^[a-f\\d]{24}$"
cronRegexString = `(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})`
spicedbIDRegexString = `^(([a-zA-Z0-9/_|\-=+]{1,})|\*)$`
spicedbPermissionRegexString = "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$"
spicedbTypeRegexString = "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$"
)
var (
@@ -90,13 +85,11 @@ var (
hslaRegex = regexp.MustCompile(hslaRegexString)
e164Regex = regexp.MustCompile(e164RegexString)
emailRegex = regexp.MustCompile(emailRegexString)
base32Regex = regexp.MustCompile(base32RegexString)
base64Regex = regexp.MustCompile(base64RegexString)
base64URLRegex = regexp.MustCompile(base64URLRegexString)
base64RawURLRegex = regexp.MustCompile(base64RawURLRegexString)
iSBN10Regex = regexp.MustCompile(iSBN10RegexString)
iSBN13Regex = regexp.MustCompile(iSBN13RegexString)
iSSNRegex = regexp.MustCompile(iSSNRegexString)
uUID3Regex = regexp.MustCompile(uUID3RegexString)
uUID4Regex = regexp.MustCompile(uUID4RegexString)
uUID5Regex = regexp.MustCompile(uUID5RegexString)
@@ -141,7 +134,4 @@ var (
cveRegex = regexp.MustCompile(cveRegexString)
mongodbRegex = regexp.MustCompile(mongodbRegexString)
cronRegex = regexp.MustCompile(cronRegexString)
spicedbIDRegex = regexp.MustCompile(spicedbIDRegexString)
spicedbPermissionRegex = regexp.MustCompile(spicedbPermissionRegexString)
spicedbTypeRegex = regexp.MustCompile(spicedbTypeRegexString)
)

View File

@@ -1,9 +1,7 @@
package validator
import (
"fmt"
"reflect"
"regexp"
"strconv"
"strings"
"time"
@@ -263,19 +261,13 @@ func asUint(param string) uint64 {
return i
}
// asFloat64 returns the parameter as a float64
// asFloat returns the parameter as a float64
// or panics if it can't convert
func asFloat64(param string) float64 {
func asFloat(param string) float64 {
i, err := strconv.ParseFloat(param, 64)
panicIf(err)
return i
}
// asFloat64 returns the parameter as a float64
// or panics if it can't convert
func asFloat32(param string) float64 {
i, err := strconv.ParseFloat(param, 32)
panicIf(err)
return i
}
@@ -294,18 +286,3 @@ func panicIf(err error) {
panic(err.Error())
}
}
// Checks if field value matches regex. If fl.Field can be cast to Stringer, it uses the Stringer interfaces
// String() return value. Otherwise, it uses fl.Field's String() value.
func fieldMatchesRegexByStringerValOrString(regex *regexp.Regexp, fl FieldLevel) bool {
switch fl.Field().Kind() {
case reflect.String:
return regex.MatchString(fl.Field().String())
default:
if stringer, ok := fl.Field().Interface().(fmt.Stringer); ok {
return regex.MatchString(stringer.String())
} else {
return regex.MatchString(fl.Field().String())
}
}
}

View File

@@ -5,7 +5,6 @@ import (
"fmt"
"reflect"
"strconv"
"unsafe"
)
// per validate construct
@@ -100,8 +99,6 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
current, kind, v.fldIsPointer = v.extractTypeInternal(current, false)
var isNestedStruct bool
switch kind {
case reflect.Ptr, reflect.Interface, reflect.Invalid:
@@ -113,10 +110,6 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
return
}
if ct.typeof == typeOmitNil && (kind != reflect.Invalid && current.IsNil()) {
return
}
if ct.hasTag {
if kind == reflect.Invalid {
v.str1 = string(append(ns, cf.altName...))
@@ -157,7 +150,7 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
structNs: v.str2,
fieldLen: uint8(len(cf.altName)),
structfieldLen: uint8(len(cf.name)),
value: getValue(current),
value: current.Interface(),
param: ct.param,
kind: kind,
typ: current.Type(),
@@ -167,61 +160,86 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
}
}
if kind == reflect.Invalid {
case reflect.Struct:
typ = current.Type()
if !typ.ConvertibleTo(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, parent, current, typ, ns, structNs, ct)
return
}
}
case reflect.Struct:
isNestedStruct = !current.Type().ConvertibleTo(timeType)
// For backward compatibility before struct level validation tags were supported
// as there were a number of projects relying on `required` not failing on non-pointer
// structs. Since it's basically nonsensical to use `required` with a non-pointer struct
// are explicitly skipping the required validation for it. This WILL be removed in the
// next major version.
if isNestedStruct && !v.v.requiredStructEnabled && ct != nil && ct.tag == requiredTag {
ct = ct.next
}
if ct == nil || !ct.hasTag {
return
}
typ = current.Type()
OUTER:
for {
if ct == nil || !ct.hasTag || (isNestedStruct && len(cf.name) == 0) {
// isNestedStruct check here
if isNestedStruct {
// 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, parent, current, typ, ns, structNs, ct)
}
if ct == nil {
return
}
switch ct.typeof {
case typeNoStructLevel:
return
case typeStructOnly:
if isNestedStruct {
// 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, parent, current, typ, ns, structNs, ct)
}
return
case typeOmitEmpty:
@@ -238,26 +256,6 @@ OUTER:
ct = ct.next
continue
case typeOmitNil:
v.slflParent = parent
v.flField = current
v.cf = cf
v.ct = ct
switch field := v.Field(); field.Kind() {
case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
if field.IsNil() {
return
}
default:
if v.fldIsPointer && field.Interface() == nil {
return
}
}
ct = ct.next
continue
case typeEndKeys:
return
@@ -368,7 +366,7 @@ OUTER:
ct = ct.next
if ct == nil {
continue OUTER
return
}
if ct.typeof != typeOr {
@@ -411,7 +409,7 @@ OUTER:
structNs: v.str2,
fieldLen: uint8(len(cf.altName)),
structfieldLen: uint8(len(cf.name)),
value: getValue(current),
value: current.Interface(),
param: ct.param,
kind: kind,
typ: typ,
@@ -431,7 +429,7 @@ OUTER:
structNs: v.str2,
fieldLen: uint8(len(cf.altName)),
structfieldLen: uint8(len(cf.name)),
value: getValue(current),
value: current.Interface(),
param: ct.param,
kind: kind,
typ: typ,
@@ -471,7 +469,7 @@ OUTER:
structNs: v.str2,
fieldLen: uint8(len(cf.altName)),
structfieldLen: uint8(len(cf.name)),
value: getValue(current),
value: current.Interface(),
param: ct.param,
kind: kind,
typ: typ,
@@ -485,26 +483,3 @@ OUTER:
}
}
func getValue(val reflect.Value) interface{} {
if val.CanInterface() {
return val.Interface()
}
if val.CanAddr() {
return reflect.NewAt(val.Type(), unsafe.Pointer(val.UnsafeAddr())).Elem().Interface()
}
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return val.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return val.Uint()
case reflect.Complex64, reflect.Complex128:
return val.Complex()
case reflect.Float32, reflect.Float64:
return val.Float()
default:
return val.String()
}
}

View File

@@ -22,7 +22,6 @@ const (
structOnlyTag = "structonly"
noStructLevelTag = "nostructlevel"
omitempty = "omitempty"
omitnil = "omitnil"
isdefault = "isdefault"
requiredWithoutAllTag = "required_without_all"
requiredWithoutTag = "required_without"
@@ -54,8 +53,6 @@ var (
timeDurationType = reflect.TypeOf(time.Duration(0))
timeType = reflect.TypeOf(time.Time{})
byteSliceType = reflect.TypeOf([]byte{})
defaultCField = &cField{namesEqual: true}
)
@@ -80,21 +77,19 @@ type internalValidationFuncWrapper struct {
// Validate contains the validator settings and cache
type Validate struct {
tagName string
pool *sync.Pool
tagNameFunc TagNameFunc
structLevelFuncs map[reflect.Type]StructLevelFuncCtx
customFuncs map[reflect.Type]CustomTypeFunc
aliases map[string]string
validations map[string]internalValidationFuncWrapper
transTagFunc map[ut.Translator]map[string]TranslationFunc // map[<locale>]map[<tag>]TranslationFunc
rules map[reflect.Type]map[string]string
tagCache *tagCache
structCache *structCache
hasCustomFuncs bool
hasTagNameFunc bool
requiredStructEnabled bool
privateFieldValidation bool
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
transTagFunc map[ut.Translator]map[string]TranslationFunc // map[<locale>]map[<tag>]TranslationFunc
rules map[reflect.Type]map[string]string
tagCache *tagCache
structCache *structCache
}
// New returns a new instance of 'validate' with sane defaults.
@@ -102,7 +97,7 @@ type Validate struct {
// It caches information about your struct and validations,
// in essence only parsing your validation tags once per struct type.
// Using multiple instances neglects the benefit of caching.
func New(options ...Option) *Validate {
func New() *Validate {
tc := new(tagCache)
tc.m.Store(make(map[string]*cTag))
@@ -149,9 +144,6 @@ func New(options ...Option) *Validate {
},
}
for _, o := range options {
o(v)
}
return v
}