mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-04-24 04:58:31 -05:00
enhancement: add graph invite endpoint (#7687)
This commit is contained in:
+2
-4
@@ -1,17 +1,15 @@
|
||||
## locales
|
||||
<img align="right" src="https://raw.githubusercontent.com/go-playground/locales/master/logo.png">
|
||||
<img align="right" src="https://raw.githubusercontent.com/go-playground/locales/master/logo.png">
|
||||
[](https://travis-ci.org/go-playground/locales)
|
||||
[](https://goreportcard.com/report/github.com/go-playground/locales)
|
||||
[](https://godoc.org/github.com/go-playground/locales)
|
||||

|
||||
[](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] Rules generated from the latest [CLDR](http://cldr.unicode.org/index/downloads) data, v36.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
|
||||
|
||||
+3
@@ -176,6 +176,7 @@ const (
|
||||
MNT
|
||||
MOP
|
||||
MRO
|
||||
MRU
|
||||
MTL
|
||||
MTP
|
||||
MUR
|
||||
@@ -262,9 +263,11 @@ const (
|
||||
UYI
|
||||
UYP
|
||||
UYU
|
||||
UYW
|
||||
UZS
|
||||
VEB
|
||||
VEF
|
||||
VES
|
||||
VND
|
||||
VNN
|
||||
VUV
|
||||
|
||||
+2
-2
@@ -55,7 +55,7 @@ func New() locales.Translator {
|
||||
perMille: "‰",
|
||||
timeSeparator: ":",
|
||||
inifinity: "∞",
|
||||
currencies: []string{"ADP", "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", "¥", "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", "$", "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"},
|
||||
currencies: []string{"ADP", "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", "¥", "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", "MRU", "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", "$", "USN", "USS", "UYI", "UYP", "UYU", "UYW", "UZS", "VEB", "VEF", "VES", "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"},
|
||||
currencyNegativePrefix: "(",
|
||||
currencyNegativeSuffix: ")",
|
||||
monthsAbbreviated: []string{"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"},
|
||||
@@ -71,7 +71,7 @@ func New() locales.Translator {
|
||||
erasAbbreviated: []string{"BC", "AD"},
|
||||
erasNarrow: []string{"B", "A"},
|
||||
erasWide: []string{"Before Christ", "Anno Domini"},
|
||||
timezones: map[string]string{"IST": "India Standard Time", "WARST": "Western Argentina Summer Time", "HNT": "Newfoundland Standard Time", "VET": "Venezuela Time", "HAST": "Hawaii-Aleutian Standard Time", "CDT": "Central Daylight Time", "HEEG": "East Greenland Summer Time", "HKT": "Hong Kong Standard Time", "SGT": "Singapore Standard Time", "EDT": "Eastern Daylight Time", "HEPM": "St. Pierre & Miquelon Daylight Time", "CST": "Central Standard Time", "HNPMX": "Mexican Pacific Standard Time", "WAT": "West Africa Standard Time", "JDT": "Japan Daylight Time", "ACST": "Australian Central Standard Time", "TMST": "Turkmenistan Summer Time", "LHDT": "Lord Howe Daylight Time", "CAT": "Central Africa Time", "UYT": "Uruguay Standard Time", "HEPMX": "Mexican Pacific Daylight Time", "WEZ": "Western European Standard Time", "BOT": "Bolivia Time", "GFT": "French Guiana Time", "HNNOMX": "Northwest Mexico Standard Time", "OEZ": "Eastern European Standard Time", "AEST": "Australian Eastern Standard Time", "MDT": "Mountain Daylight Time", "SAST": "South Africa Standard Time", "BT": "Bhutan Time", "SRT": "Suriname Time", "TMT": "Turkmenistan Standard Time", "CHADT": "Chatham Daylight Time", "PST": "Pacific Standard Time", "ADT": "Atlantic Daylight Time", "HENOMX": "Northwest Mexico Daylight Time", "EAT": "East Africa Time", "CLT": "Chile Standard Time", "∅∅∅": "Brasilia Summer Time", "WESZ": "Western European Summer Time", "HAT": "Newfoundland Daylight Time", "WIB": "Western Indonesia Time", "NZST": "New Zealand Standard Time", "HNEG": "East Greenland Standard Time", "HNPM": "St. Pierre & Miquelon Standard Time", "WITA": "Central Indonesia Time", "GMT": "Greenwich Mean Time", "UYST": "Uruguay Summer Time", "HNCU": "Cuba Standard Time", "GYT": "Guyana Time", "MYT": "Malaysia Time", "COT": "Colombia Standard Time", "AST": "Atlantic Standard Time", "ACDT": "Australian Central Daylight Time", "MEZ": "Central European Standard Time", "AKDT": "Alaska Daylight Time", "EST": "Eastern Standard Time", "HNOG": "West Greenland Standard Time", "ECT": "Ecuador Time", "ART": "Argentina Standard Time", "HEOG": "West Greenland Summer Time", "MESZ": "Central European Summer Time", "LHST": "Lord Howe Standard Time", "OESZ": "Eastern European Summer Time", "AWST": "Australian Western Standard Time", "AEDT": "Australian Eastern Daylight Time", "ACWDT": "Australian Central Western Daylight Time", "NZDT": "New Zealand Daylight Time", "JST": "Japan Standard Time", "WART": "Western Argentina Standard Time", "CHAST": "Chatham Standard Time", "HECU": "Cuba Daylight Time", "WAST": "West Africa Summer Time", "ACWST": "Australian Central Western Standard Time", "HKST": "Hong Kong Summer Time", "ARST": "Argentina Summer Time", "MST": "Mountain Standard Time", "AKST": "Alaska Standard Time", "CLST": "Chile Summer Time", "WIT": "Eastern Indonesia Time", "HADT": "Hawaii-Aleutian Daylight Time", "ChST": "Chamorro Standard Time", "PDT": "Pacific Daylight Time", "AWDT": "Australian Western Daylight Time", "COST": "Colombia Summer Time"},
|
||||
timezones: map[string]string{"ACDT": "Australian Central Daylight Time", "ACST": "Australian Central Standard Time", "ACWDT": "Australian Central Western Daylight Time", "ACWST": "Australian Central Western Standard Time", "ADT": "Atlantic Daylight Time", "AEDT": "Australian Eastern Daylight Time", "AEST": "Australian Eastern Standard Time", "AKDT": "Alaska Daylight Time", "AKST": "Alaska Standard Time", "ARST": "Argentina Summer Time", "ART": "Argentina Standard Time", "AST": "Atlantic Standard Time", "AWDT": "Australian Western Daylight Time", "AWST": "Australian Western Standard Time", "BOT": "Bolivia Time", "BT": "Bhutan Time", "CAT": "Central Africa Time", "CDT": "Central Daylight Time", "CHADT": "Chatham Daylight Time", "CHAST": "Chatham Standard Time", "CLST": "Chile Summer Time", "CLT": "Chile Standard Time", "COST": "Colombia Summer Time", "COT": "Colombia Standard Time", "CST": "Central Standard Time", "ChST": "Chamorro Standard Time", "EAT": "East Africa Time", "ECT": "Ecuador Time", "EDT": "Eastern Daylight Time", "EST": "Eastern Standard Time", "GFT": "French Guiana Time", "GMT": "Greenwich Mean Time", "GST": "Gulf Standard Time", "GYT": "Guyana Time", "HADT": "Hawaii-Aleutian Daylight Time", "HAST": "Hawaii-Aleutian Standard Time", "HAT": "Newfoundland Daylight Time", "HECU": "Cuba Daylight Time", "HEEG": "East Greenland Summer Time", "HENOMX": "Northwest Mexico Daylight Time", "HEOG": "West Greenland Summer Time", "HEPM": "St. Pierre & Miquelon Daylight Time", "HEPMX": "Mexican Pacific Daylight Time", "HKST": "Hong Kong Summer Time", "HKT": "Hong Kong Standard Time", "HNCU": "Cuba Standard Time", "HNEG": "East Greenland Standard Time", "HNNOMX": "Northwest Mexico Standard Time", "HNOG": "West Greenland Standard Time", "HNPM": "St. Pierre & Miquelon Standard Time", "HNPMX": "Mexican Pacific Standard Time", "HNT": "Newfoundland Standard Time", "IST": "India Standard Time", "JDT": "Japan Daylight Time", "JST": "Japan Standard Time", "LHDT": "Lord Howe Daylight Time", "LHST": "Lord Howe Standard Time", "MDT": "Mountain Daylight Time", "MESZ": "Central European Summer Time", "MEZ": "Central European Standard Time", "MST": "Mountain Standard Time", "MYT": "Malaysia Time", "NZDT": "New Zealand Daylight Time", "NZST": "New Zealand Standard Time", "OESZ": "Eastern European Summer Time", "OEZ": "Eastern European Standard Time", "PDT": "Pacific Daylight Time", "PST": "Pacific Standard Time", "SAST": "South Africa Standard Time", "SGT": "Singapore Standard Time", "SRT": "Suriname Time", "TMST": "Turkmenistan Summer Time", "TMT": "Turkmenistan Standard Time", "UYST": "Uruguay Summer Time", "UYT": "Uruguay Standard Time", "VET": "Venezuela Time", "WARST": "Western Argentina Summer Time", "WART": "Western Argentina Standard Time", "WAST": "West Africa Summer Time", "WAT": "West Africa Standard Time", "WESZ": "Western European Summer Time", "WEZ": "Western European Standard Time", "WIB": "Western Indonesia Time", "WIT": "Eastern Indonesia Time", "WITA": "Central Indonesia Time", "∅∅∅": "Brasilia Summer Time"},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
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.41.1; \
|
||||
}
|
||||
|
||||
lint: linters-install
|
||||
golangci-lint run
|
||||
|
||||
test:
|
||||
$(GOCMD) test -cover -race ./...
|
||||
|
||||
bench:
|
||||
$(GOCMD) test -bench=. -benchmem ./...
|
||||
|
||||
.PHONY: test lint linters-install
|
||||
+3
-5
@@ -1,11 +1,9 @@
|
||||
## universal-translator
|
||||
<img align="right" src="https://raw.githubusercontent.com/go-playground/universal-translator/master/logo.png">
|
||||
[](https://travis-ci.org/go-playground/universal-translator)
|
||||
<img align="right" src="https://raw.githubusercontent.com/go-playground/universal-translator/master/logo.png">
|
||||
[](https://coveralls.io/github/go-playground/universal-translator)
|
||||
[](https://goreportcard.com/report/github.com/go-playground/universal-translator)
|
||||
[](https://godoc.org/github.com/go-playground/universal-translator)
|
||||

|
||||
[](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
|
||||
|
||||
@@ -18,7 +16,7 @@ use in your applications.
|
||||
|
||||
Features
|
||||
--------
|
||||
- [x] Rules generated from the [CLDR](http://cldr.unicode.org/index/downloads) data, v30.0.3
|
||||
- [x] Rules generated from the [CLDR](http://cldr.unicode.org/index/downloads) data, v36.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
|
||||
@@ -51,7 +49,7 @@ Please see https://godoc.org/github.com/go-playground/universal-translator for u
|
||||
|
||||
File formatting
|
||||
--------------
|
||||
All types, Plain substitution, Cardinal, Ordinal and Range translations can all be contained withing the same file(s);
|
||||
All types, Plain substitution, Cardinal, Ordinal and Range translations can all be contained within the same file(s);
|
||||
they are only separated for easy viewing.
|
||||
|
||||
##### Examples:
|
||||
|
||||
+4
-4
@@ -3,7 +3,6 @@ package ut
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -41,7 +40,6 @@ const (
|
||||
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) {
|
||||
@@ -138,7 +136,7 @@ func (t *UniversalTranslator) Export(format ImportExportFormat, dirname string)
|
||||
return err
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(dirname, fmt.Sprintf("%s%s", locale.Locale(), ext)), b, 0644)
|
||||
err = os.WriteFile(filepath.Join(dirname, fmt.Sprintf("%s%s", locale.Locale(), ext)), b, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -200,7 +198,7 @@ func (t *UniversalTranslator) Import(format ImportExportFormat, dirnameOrFilenam
|
||||
// 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)
|
||||
b, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -257,6 +255,8 @@ func (t *UniversalTranslator) ImportByReader(format ImportExportFormat, reader i
|
||||
func stringToPR(s string) locales.PluralRule {
|
||||
|
||||
switch s {
|
||||
case "Zero":
|
||||
return locales.PluralRuleZero
|
||||
case "One":
|
||||
return locales.PluralRuleOne
|
||||
case "Two":
|
||||
|
||||
+6
-6
@@ -159,13 +159,13 @@ func (t *translator) AddCardinal(key interface{}, text string, rule locales.Plur
|
||||
}
|
||||
|
||||
} else {
|
||||
tarr = make([]*transText, 7, 7)
|
||||
tarr = make([]*transText, 7)
|
||||
t.cardinalTanslations[key] = tarr
|
||||
}
|
||||
|
||||
trans := &transText{
|
||||
text: text,
|
||||
indexes: make([]int, 2, 2),
|
||||
indexes: make([]int, 2),
|
||||
}
|
||||
|
||||
tarr[rule] = trans
|
||||
@@ -211,13 +211,13 @@ func (t *translator) AddOrdinal(key interface{}, text string, rule locales.Plura
|
||||
}
|
||||
|
||||
} else {
|
||||
tarr = make([]*transText, 7, 7)
|
||||
tarr = make([]*transText, 7)
|
||||
t.ordinalTanslations[key] = tarr
|
||||
}
|
||||
|
||||
trans := &transText{
|
||||
text: text,
|
||||
indexes: make([]int, 2, 2),
|
||||
indexes: make([]int, 2),
|
||||
}
|
||||
|
||||
tarr[rule] = trans
|
||||
@@ -261,13 +261,13 @@ func (t *translator) AddRange(key interface{}, text string, rule locales.PluralR
|
||||
}
|
||||
|
||||
} else {
|
||||
tarr = make([]*transText, 7, 7)
|
||||
tarr = make([]*transText, 7)
|
||||
t.rangeTanslations[key] = tarr
|
||||
}
|
||||
|
||||
trans := &transText{
|
||||
text: text,
|
||||
indexes: make([]int, 4, 4),
|
||||
indexes: make([]int, 4),
|
||||
}
|
||||
|
||||
tarr[rule] = trans
|
||||
|
||||
@@ -26,5 +26,7 @@ _testmain.go
|
||||
*.test
|
||||
*.out
|
||||
*.txt
|
||||
/**/*.DS_Store
|
||||
cover.html
|
||||
README.html
|
||||
.idea
|
||||
|
||||
-29
@@ -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
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
## Maintainers Guide
|
||||
|
||||
### Semantic Versioning
|
||||
Semantic versioning as defined [here](https://semver.org) must be strictly adhered to.
|
||||
|
||||
### External Dependencies
|
||||
Any new external dependencies MUST:
|
||||
- Have a compatible LICENSE present.
|
||||
- Be actively maintained.
|
||||
- Be approved by @go-playground/admins
|
||||
|
||||
### PR Merge Requirements
|
||||
- Up-to-date branch.
|
||||
- Passing tests and linting.
|
||||
- CODEOWNERS approval.
|
||||
- Tests that cover both the Happy and Unhappy paths.
|
||||
+3
-3
@@ -3,16 +3,16 @@ 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; \
|
||||
curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.41.1; \
|
||||
}
|
||||
|
||||
lint: linters-install
|
||||
$(PWD)/bin/golangci-lint run
|
||||
golangci-lint run
|
||||
|
||||
test:
|
||||
$(GOCMD) test -cover -race ./...
|
||||
|
||||
bench:
|
||||
$(GOCMD) test -bench=. -benchmem ./...
|
||||
$(GOCMD) test -run=NONE -bench=. -benchmem ./...
|
||||
|
||||
.PHONY: test lint linters-install
|
||||
+140
-81
@@ -1,7 +1,7 @@
|
||||
Package validator
|
||||
================
|
||||
<img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||

|
||||
=================
|
||||
<img align="right" src="logo.png">[](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||

|
||||
[](https://travis-ci.org/go-playground/validator)
|
||||
[](https://coveralls.io/github/go-playground/validator?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/go-playground/validator)
|
||||
@@ -43,7 +43,7 @@ They return type error to avoid the issue discussed in the following, where err
|
||||
* 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:
|
||||
Validator returns 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)
|
||||
@@ -53,7 +53,7 @@ validationErrors := err.(validator.ValidationErrors)
|
||||
Usage and documentation
|
||||
------
|
||||
|
||||
Please see https://godoc.org/github.com/go-playground/validator for detailed usage docs.
|
||||
Please see https://pkg.go.dev/github.com/go-playground/validator/v10 for detailed usage docs.
|
||||
|
||||
##### Examples:
|
||||
|
||||
@@ -67,14 +67,20 @@ Please see https://godoc.org/github.com/go-playground/validator for detailed usa
|
||||
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 |
|
||||
| - | - |
|
||||
| eqcsfield | Field Equals Another Field (relative)|
|
||||
| eqfield | Field Equals Another Field |
|
||||
| fieldcontains | NOT DOCUMENTED IN doc.go |
|
||||
| fieldexcludes | NOT DOCUMENTED IN doc.go |
|
||||
| fieldcontains | Check the indicated characters are present in the Field |
|
||||
| fieldexcludes | Check the indicated characters are not present in the field |
|
||||
| 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 |
|
||||
@@ -100,7 +106,7 @@ Baked-in Validations
|
||||
| hostname_rfc1123 | Hostname RFC 1123 |
|
||||
| ip | Internet Protocol Address IP |
|
||||
| ip4_addr | Internet Protocol Address IPv4 |
|
||||
| ip6_addr |Internet Protocol Address IPv6 |
|
||||
| ip6_addr | Internet Protocol Address IPv6 |
|
||||
| ip_addr | Internet Protocol Address IP |
|
||||
| ipv4 | Internet Protocol Address IPv4 |
|
||||
| ipv6 | Internet Protocol Address IPv6 |
|
||||
@@ -114,6 +120,7 @@ Baked-in Validations
|
||||
| unix_addr | Unix domain socket end point Address |
|
||||
| uri | URI String |
|
||||
| url | URL String |
|
||||
| http_url | HTTP URL String |
|
||||
| url_encoded | URL Encoded |
|
||||
| urn_rfc2141 | Urn RFC 2141 String |
|
||||
|
||||
@@ -126,15 +133,21 @@ Baked-in Validations
|
||||
| alphanumunicode | Alphanumeric Unicode |
|
||||
| alphaunicode | Alpha Unicode |
|
||||
| ascii | ASCII |
|
||||
| boolean | Boolean |
|
||||
| contains | Contains |
|
||||
| containsany | Contains Any |
|
||||
| containsrune | Contains Rune |
|
||||
| endsnotwith | Ends Not With |
|
||||
| endswith | Ends With |
|
||||
| excludes | Excludes |
|
||||
| excludesall | Excludes All |
|
||||
| excludesrune | Excludes Rune |
|
||||
| lowercase | Lowercase |
|
||||
| multibyte | Multi-Byte Characters |
|
||||
| number | NOT DOCUMENTED IN doc.go |
|
||||
| number | Number |
|
||||
| numeric | Numeric |
|
||||
| printascii | Printable ASCII |
|
||||
| startsnotwith | Starts Not With |
|
||||
| startswith | Starts With |
|
||||
| uppercase | Uppercase |
|
||||
|
||||
@@ -143,8 +156,15 @@ Baked-in Validations
|
||||
| - | - |
|
||||
| base64 | Base64 String |
|
||||
| base64url | Base64URL String |
|
||||
| base64rawurl | Base64RawURL String |
|
||||
| bic | Business Identifier Code (ISO 9362) |
|
||||
| bcp47_language_tag | Language tag (BCP 47) |
|
||||
| btc_addr | Bitcoin Address |
|
||||
| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |
|
||||
| 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
|
||||
@@ -158,12 +178,23 @@ Baked-in Validations
|
||||
| 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) |
|
||||
| iso3166_2 | Country subdivision code (ISO 3166-2) |
|
||||
| iso4217 | Currency code (ISO 4217) |
|
||||
| json | JSON |
|
||||
| jwt | JSON Web Token (JWT) |
|
||||
| latitude | Latitude |
|
||||
| longitude | Longitude |
|
||||
| luhn_checksum | Luhn Algorithm Checksum (for strings and (u)int) |
|
||||
| postcode_iso3166_alpha2 | Postcode |
|
||||
| postcode_iso3166_alpha2_field | Postcode |
|
||||
| rgb | RGB String |
|
||||
| rgba | RGBA String |
|
||||
| ssn | Social Security Number SSN |
|
||||
| timezone | Timezone |
|
||||
| uuid | Universally Unique Identifier UUID |
|
||||
| uuid3 | Universally Unique Identifier UUID v3 |
|
||||
| uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 |
|
||||
@@ -172,26 +203,40 @@ Baked-in Validations
|
||||
| uuid5 | Universally Unique Identifier UUID v5 |
|
||||
| uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 |
|
||||
| uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 |
|
||||
| md4 | MD4 hash |
|
||||
| md5 | MD5 hash |
|
||||
| sha256 | SHA256 hash |
|
||||
| sha384 | SHA384 hash |
|
||||
| sha512 | SHA512 hash |
|
||||
| ripemd128 | RIPEMD-128 hash |
|
||||
| ripemd128 | RIPEMD-160 hash |
|
||||
| tiger128 | TIGER128 hash |
|
||||
| tiger160 | TIGER160 hash |
|
||||
| tiger192 | TIGER192 hash |
|
||||
| semver | Semantic Versioning 2.0.0 |
|
||||
| ulid | Universally Unique Lexicographically Sortable Identifier ULID |
|
||||
| cve | Common Vulnerabilities and Exposures Identifier (CVE id) |
|
||||
|
||||
### Comparisons:
|
||||
| Tag | Description |
|
||||
| - | - |
|
||||
| eq | Equals |
|
||||
| eq_ignore_case | Equals ignoring case |
|
||||
| gt | Greater than|
|
||||
| gte |Greater than or equal |
|
||||
| gte | Greater than or equal |
|
||||
| lt | Less Than |
|
||||
| lte | Less Than or Equal |
|
||||
| ne | Not Equal |
|
||||
| ne_ignore_case | Not Equal ignoring case |
|
||||
|
||||
### Other:
|
||||
| Tag | Description |
|
||||
| - | - |
|
||||
| dir | Directory |
|
||||
| endswith | Ends With |
|
||||
| excludes | Excludes |
|
||||
| excludesall | Excludes All |
|
||||
| excludesrune | Excludes Rune |
|
||||
| file | File path |
|
||||
| dir | Existing Directory |
|
||||
| dirpath | Directory Path |
|
||||
| file | Existing File |
|
||||
| filepath | File Path |
|
||||
| image | Image |
|
||||
| isdefault | Is Default |
|
||||
| len | Length |
|
||||
| max | Maximum |
|
||||
@@ -204,81 +249,90 @@ Baked-in Validations
|
||||
| required_with_all | Required With All |
|
||||
| required_without | Required Without |
|
||||
| required_without_all | Required Without All |
|
||||
| excluded_if | Excluded If |
|
||||
| excluded_unless | Excluded Unless |
|
||||
| excluded_with | Excluded With |
|
||||
| excluded_with_all | Excluded With All |
|
||||
| excluded_without | Excluded Without |
|
||||
| excluded_without_all | Excluded Without All |
|
||||
| unique | Unique |
|
||||
|
||||
#### Aliases:
|
||||
| Tag | Description |
|
||||
| - | - |
|
||||
| iscolor | hexcolor\|rgb\|rgba\|hsl\|hsla |
|
||||
| country_code | iso3166_1_alpha2\|iso3166_1_alpha3\|iso3166_1_alpha_numeric |
|
||||
|
||||
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: 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
|
||||
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
|
||||
```
|
||||
|
||||
Complementary Software
|
||||
@@ -295,5 +349,10 @@ How to Contribute
|
||||
Make a pull request...
|
||||
|
||||
License
|
||||
------
|
||||
-------
|
||||
Distributed under MIT License, please see license file within the code for more details.
|
||||
|
||||
Maintainers
|
||||
-----------
|
||||
This project has grown large enough that more than one person is required to properly support the community.
|
||||
If you are interested in becoming a maintainer please reach out to me https://github.com/deankarn
|
||||
|
||||
+1099
-429
File diff suppressed because it is too large
Load Diff
+11
-1
@@ -20,6 +20,7 @@ const (
|
||||
typeOr
|
||||
typeKeys
|
||||
typeEndKeys
|
||||
typeOmitNil
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -114,6 +115,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
|
||||
cs = &cStruct{name: sName, fields: make([]*cField, 0), fn: v.structLevelFuncs[typ]}
|
||||
|
||||
numFields := current.NumField()
|
||||
rules := v.rules[typ]
|
||||
|
||||
var ctag *cTag
|
||||
var fld reflect.StructField
|
||||
@@ -128,7 +130,11 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
|
||||
continue
|
||||
}
|
||||
|
||||
tag = fld.Tag.Get(v.tagName)
|
||||
if rtag, ok := rules[fld.Name]; ok {
|
||||
tag = rtag
|
||||
} else {
|
||||
tag = fld.Tag.Get(v.tagName)
|
||||
}
|
||||
|
||||
if tag == skipValidationTag {
|
||||
continue
|
||||
@@ -247,6 +253,10 @@ 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
|
||||
|
||||
+991
-3
File diff suppressed because it is too large
Load Diff
+79
@@ -0,0 +1,79 @@
|
||||
package validator
|
||||
|
||||
var iso4217 = map[string]bool{
|
||||
"AFN": true, "EUR": true, "ALL": true, "DZD": true, "USD": true,
|
||||
"AOA": true, "XCD": true, "ARS": true, "AMD": true, "AWG": true,
|
||||
"AUD": true, "AZN": true, "BSD": true, "BHD": true, "BDT": true,
|
||||
"BBD": true, "BYN": true, "BZD": true, "XOF": true, "BMD": true,
|
||||
"INR": true, "BTN": true, "BOB": true, "BOV": true, "BAM": true,
|
||||
"BWP": true, "NOK": true, "BRL": true, "BND": true, "BGN": true,
|
||||
"BIF": true, "CVE": true, "KHR": true, "XAF": true, "CAD": true,
|
||||
"KYD": true, "CLP": true, "CLF": true, "CNY": true, "COP": true,
|
||||
"COU": true, "KMF": true, "CDF": true, "NZD": true, "CRC": true,
|
||||
"HRK": true, "CUP": true, "CUC": true, "ANG": true, "CZK": true,
|
||||
"DKK": true, "DJF": true, "DOP": true, "EGP": true, "SVC": true,
|
||||
"ERN": true, "SZL": true, "ETB": true, "FKP": true, "FJD": true,
|
||||
"XPF": true, "GMD": true, "GEL": true, "GHS": true, "GIP": true,
|
||||
"GTQ": true, "GBP": true, "GNF": true, "GYD": true, "HTG": true,
|
||||
"HNL": true, "HKD": true, "HUF": true, "ISK": true, "IDR": true,
|
||||
"XDR": true, "IRR": true, "IQD": true, "ILS": true, "JMD": true,
|
||||
"JPY": true, "JOD": true, "KZT": true, "KES": true, "KPW": true,
|
||||
"KRW": true, "KWD": true, "KGS": true, "LAK": true, "LBP": true,
|
||||
"LSL": true, "ZAR": true, "LRD": true, "LYD": true, "CHF": true,
|
||||
"MOP": true, "MKD": true, "MGA": true, "MWK": true, "MYR": true,
|
||||
"MVR": true, "MRU": true, "MUR": true, "XUA": true, "MXN": true,
|
||||
"MXV": true, "MDL": true, "MNT": true, "MAD": true, "MZN": true,
|
||||
"MMK": true, "NAD": true, "NPR": true, "NIO": true, "NGN": true,
|
||||
"OMR": true, "PKR": true, "PAB": true, "PGK": true, "PYG": true,
|
||||
"PEN": true, "PHP": true, "PLN": true, "QAR": true, "RON": true,
|
||||
"RUB": true, "RWF": true, "SHP": true, "WST": true, "STN": true,
|
||||
"SAR": true, "RSD": true, "SCR": true, "SLL": true, "SGD": true,
|
||||
"XSU": true, "SBD": true, "SOS": true, "SSP": true, "LKR": true,
|
||||
"SDG": true, "SRD": true, "SEK": true, "CHE": true, "CHW": true,
|
||||
"SYP": true, "TWD": true, "TJS": true, "TZS": true, "THB": true,
|
||||
"TOP": true, "TTD": true, "TND": true, "TRY": true, "TMT": true,
|
||||
"UGX": true, "UAH": true, "AED": true, "USN": true, "UYU": true,
|
||||
"UYI": true, "UYW": true, "UZS": true, "VUV": true, "VES": true,
|
||||
"VND": true, "YER": true, "ZMW": true, "ZWL": true, "XBA": true,
|
||||
"XBB": true, "XBC": true, "XBD": true, "XTS": true, "XXX": true,
|
||||
"XAU": true, "XPD": true, "XPT": true, "XAG": true,
|
||||
}
|
||||
|
||||
var iso4217_numeric = map[int]bool{
|
||||
8: true, 12: true, 32: true, 36: true, 44: true,
|
||||
48: true, 50: true, 51: true, 52: true, 60: true,
|
||||
64: true, 68: true, 72: true, 84: true, 90: true,
|
||||
96: true, 104: true, 108: true, 116: true, 124: true,
|
||||
132: true, 136: true, 144: true, 152: true, 156: true,
|
||||
170: true, 174: true, 188: true, 191: true, 192: true,
|
||||
203: true, 208: true, 214: true, 222: true, 230: true,
|
||||
232: true, 238: true, 242: true, 262: true, 270: true,
|
||||
292: true, 320: true, 324: true, 328: true, 332: true,
|
||||
340: true, 344: true, 348: true, 352: true, 356: true,
|
||||
360: true, 364: true, 368: true, 376: true, 388: true,
|
||||
392: true, 398: true, 400: true, 404: true, 408: true,
|
||||
410: true, 414: true, 417: true, 418: true, 422: true,
|
||||
426: true, 430: true, 434: true, 446: true, 454: true,
|
||||
458: true, 462: true, 480: true, 484: true, 496: true,
|
||||
498: true, 504: true, 512: true, 516: true, 524: true,
|
||||
532: true, 533: true, 548: true, 554: true, 558: true,
|
||||
566: true, 578: true, 586: true, 590: true, 598: true,
|
||||
600: true, 604: true, 608: true, 634: true, 643: true,
|
||||
646: true, 654: true, 682: true, 690: true, 694: true,
|
||||
702: true, 704: true, 706: true, 710: true, 728: true,
|
||||
748: true, 752: true, 756: true, 760: true, 764: true,
|
||||
776: true, 780: true, 784: true, 788: true, 800: true,
|
||||
807: true, 818: true, 826: true, 834: true, 840: true,
|
||||
858: true, 860: true, 882: true, 886: true, 901: true,
|
||||
927: true, 928: true, 929: true, 930: true, 931: true,
|
||||
932: true, 933: true, 934: true, 936: true, 938: true,
|
||||
940: true, 941: true, 943: true, 944: true, 946: true,
|
||||
947: true, 948: true, 949: true, 950: true, 951: true,
|
||||
952: true, 953: true, 955: true, 956: true, 957: true,
|
||||
958: true, 959: true, 960: true, 961: true, 962: true,
|
||||
963: true, 964: true, 965: true, 967: true, 968: true,
|
||||
969: true, 970: true, 971: true, 972: true, 973: true,
|
||||
975: true, 976: true, 977: true, 978: true, 979: true,
|
||||
980: true, 981: true, 984: true, 985: true, 986: true,
|
||||
990: true, 994: true, 997: true, 999: true,
|
||||
}
|
||||
+322
-156
File diff suppressed because it is too large
Load Diff
+12
-15
@@ -44,12 +44,9 @@ 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(ve[i].Error())
|
||||
buff.WriteString("\n")
|
||||
}
|
||||
|
||||
@@ -82,7 +79,7 @@ func (ve ValidationErrors) Translate(ut ut.Translator) ValidationErrorsTranslati
|
||||
// FieldError contains all functions to get error details
|
||||
type FieldError interface {
|
||||
|
||||
// returns the validation tag that failed. if the
|
||||
// Tag 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.
|
||||
//
|
||||
@@ -90,7 +87,7 @@ type FieldError interface {
|
||||
// will return "iscolor"
|
||||
Tag() string
|
||||
|
||||
// returns the validation tag that failed, even if an
|
||||
// ActualTag 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.
|
||||
//
|
||||
@@ -98,7 +95,7 @@ type FieldError interface {
|
||||
// will return "hexcolor|rgb|rgba|hsl|hsla"
|
||||
ActualTag() string
|
||||
|
||||
// returns the namespace for the field error, with the tag
|
||||
// Namespace returns the namespace for the field error, with the tag
|
||||
// name taking precedence over the field's actual name.
|
||||
//
|
||||
// eg. JSON name "User.fname"
|
||||
@@ -109,7 +106,7 @@ type FieldError interface {
|
||||
// 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
|
||||
// StructNamespace returns the namespace for the field error, with the field's
|
||||
// actual name.
|
||||
//
|
||||
// eq. "User.FirstName" see Namespace for comparison
|
||||
@@ -118,24 +115,24 @@ type FieldError interface {
|
||||
// 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 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.
|
||||
// StructField 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
|
||||
// Value 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
|
||||
// Param returns the param value, in string form for comparison; this will also
|
||||
// help with generating an error message
|
||||
Param() string
|
||||
|
||||
@@ -146,10 +143,10 @@ type FieldError interface {
|
||||
|
||||
// Type returns the Field's reflect Type
|
||||
//
|
||||
// // eg. time.Time's type is time.Time
|
||||
// eg. time.Time's type is time.Time
|
||||
Type() reflect.Type
|
||||
|
||||
// returns the FieldError's translated error
|
||||
// Translate 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
|
||||
@@ -221,7 +218,7 @@ func (fe *fieldError) Field() string {
|
||||
// return fld
|
||||
}
|
||||
|
||||
// returns the field's actual name from the struct, when able to determine.
|
||||
// StructField 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):]
|
||||
|
||||
+12
-11
@@ -5,24 +5,25 @@ 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 returns the top level struct, if any
|
||||
Top() reflect.Value
|
||||
|
||||
// returns the current fields parent struct, if any or
|
||||
// Parent returns the current fields parent struct, if any or
|
||||
// the comparison value if called 'VarWithValue'
|
||||
Parent() reflect.Value
|
||||
|
||||
// returns current field for validation
|
||||
// Field returns current field for validation
|
||||
Field() reflect.Value
|
||||
|
||||
// returns the field's name with the tag
|
||||
// FieldName 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 returns the struct field's name
|
||||
StructFieldName() string
|
||||
|
||||
// returns param for validation against current field
|
||||
// Param returns param for validation against current field
|
||||
Param() string
|
||||
|
||||
// GetTag returns the current validations tag name
|
||||
@@ -33,7 +34,7 @@ type FieldLevel interface {
|
||||
// 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
|
||||
// GetStructFieldOK 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.
|
||||
//
|
||||
@@ -49,7 +50,7 @@ type FieldLevel interface {
|
||||
// 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
|
||||
// GetStructFieldOK2 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.
|
||||
//
|
||||
@@ -57,7 +58,7 @@ type FieldLevel interface {
|
||||
// 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
|
||||
// GetStructFieldOKAdvanced2 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)
|
||||
}
|
||||
@@ -107,12 +108,12 @@ func (v *validate) GetStructFieldOKAdvanced(val reflect.Value, namespace string)
|
||||
return current, kind, found
|
||||
}
|
||||
|
||||
// GetStructFieldOK returns Param returns param for validation against current field
|
||||
// GetStructFieldOK2 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
|
||||
// GetStructFieldOKAdvanced2 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)
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package validator
|
||||
|
||||
// Option represents a configurations option to be applied to validator during initialization.
|
||||
type Option func(*Validate)
|
||||
|
||||
// WithRequiredStructEnabled enables required tag on non-pointer structs to be applied instead of ignored.
|
||||
//
|
||||
// This was made opt-in behaviour in order to maintain backward compatibility with the behaviour previous
|
||||
// to being able to apply struct level validations on struct fields directly.
|
||||
//
|
||||
// It is recommended you enabled this as it will be the default behaviour in v11+
|
||||
func WithRequiredStructEnabled() Option {
|
||||
return func(v *Validate) {
|
||||
v.requiredStructEnabled = true
|
||||
}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
package validator
|
||||
|
||||
import "regexp"
|
||||
|
||||
var postCodePatternDict = map[string]string{
|
||||
"GB": `^GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\d{1,4}$`,
|
||||
"JE": `^JE\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`,
|
||||
"GG": `^GY\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`,
|
||||
"IM": `^IM\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`,
|
||||
"US": `^\d{5}([ \-]\d{4})?$`,
|
||||
"CA": `^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][ ]?\d[ABCEGHJ-NPRSTV-Z]\d$`,
|
||||
"DE": `^\d{5}$`,
|
||||
"JP": `^\d{3}-\d{4}$`,
|
||||
"FR": `^\d{2}[ ]?\d{3}$`,
|
||||
"AU": `^\d{4}$`,
|
||||
"IT": `^\d{5}$`,
|
||||
"CH": `^\d{4}$`,
|
||||
"AT": `^\d{4}$`,
|
||||
"ES": `^\d{5}$`,
|
||||
"NL": `^\d{4}[ ]?[A-Z]{2}$`,
|
||||
"BE": `^\d{4}$`,
|
||||
"DK": `^\d{4}$`,
|
||||
"SE": `^\d{3}[ ]?\d{2}$`,
|
||||
"NO": `^\d{4}$`,
|
||||
"BR": `^\d{5}[\-]?\d{3}$`,
|
||||
"PT": `^\d{4}([\-]\d{3})?$`,
|
||||
"FI": `^\d{5}$`,
|
||||
"AX": `^22\d{3}$`,
|
||||
"KR": `^\d{3}[\-]\d{3}$`,
|
||||
"CN": `^\d{6}$`,
|
||||
"TW": `^\d{3}(\d{2})?$`,
|
||||
"SG": `^\d{6}$`,
|
||||
"DZ": `^\d{5}$`,
|
||||
"AD": `^AD\d{3}$`,
|
||||
"AR": `^([A-HJ-NP-Z])?\d{4}([A-Z]{3})?$`,
|
||||
"AM": `^(37)?\d{4}$`,
|
||||
"AZ": `^\d{4}$`,
|
||||
"BH": `^((1[0-2]|[2-9])\d{2})?$`,
|
||||
"BD": `^\d{4}$`,
|
||||
"BB": `^(BB\d{5})?$`,
|
||||
"BY": `^\d{6}$`,
|
||||
"BM": `^[A-Z]{2}[ ]?[A-Z0-9]{2}$`,
|
||||
"BA": `^\d{5}$`,
|
||||
"IO": `^BBND 1ZZ$`,
|
||||
"BN": `^[A-Z]{2}[ ]?\d{4}$`,
|
||||
"BG": `^\d{4}$`,
|
||||
"KH": `^\d{5}$`,
|
||||
"CV": `^\d{4}$`,
|
||||
"CL": `^\d{7}$`,
|
||||
"CR": `^\d{4,5}|\d{3}-\d{4}$`,
|
||||
"HR": `^\d{5}$`,
|
||||
"CY": `^\d{4}$`,
|
||||
"CZ": `^\d{3}[ ]?\d{2}$`,
|
||||
"DO": `^\d{5}$`,
|
||||
"EC": `^([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?$`,
|
||||
"EG": `^\d{5}$`,
|
||||
"EE": `^\d{5}$`,
|
||||
"FO": `^\d{3}$`,
|
||||
"GE": `^\d{4}$`,
|
||||
"GR": `^\d{3}[ ]?\d{2}$`,
|
||||
"GL": `^39\d{2}$`,
|
||||
"GT": `^\d{5}$`,
|
||||
"HT": `^\d{4}$`,
|
||||
"HN": `^(?:\d{5})?$`,
|
||||
"HU": `^\d{4}$`,
|
||||
"IS": `^\d{3}$`,
|
||||
"IN": `^\d{6}$`,
|
||||
"ID": `^\d{5}$`,
|
||||
"IL": `^\d{5}$`,
|
||||
"JO": `^\d{5}$`,
|
||||
"KZ": `^\d{6}$`,
|
||||
"KE": `^\d{5}$`,
|
||||
"KW": `^\d{5}$`,
|
||||
"LA": `^\d{5}$`,
|
||||
"LV": `^\d{4}$`,
|
||||
"LB": `^(\d{4}([ ]?\d{4})?)?$`,
|
||||
"LI": `^(948[5-9])|(949[0-7])$`,
|
||||
"LT": `^\d{5}$`,
|
||||
"LU": `^\d{4}$`,
|
||||
"MK": `^\d{4}$`,
|
||||
"MY": `^\d{5}$`,
|
||||
"MV": `^\d{5}$`,
|
||||
"MT": `^[A-Z]{3}[ ]?\d{2,4}$`,
|
||||
"MU": `^(\d{3}[A-Z]{2}\d{3})?$`,
|
||||
"MX": `^\d{5}$`,
|
||||
"MD": `^\d{4}$`,
|
||||
"MC": `^980\d{2}$`,
|
||||
"MA": `^\d{5}$`,
|
||||
"NP": `^\d{5}$`,
|
||||
"NZ": `^\d{4}$`,
|
||||
"NI": `^((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?$`,
|
||||
"NG": `^(\d{6})?$`,
|
||||
"OM": `^(PC )?\d{3}$`,
|
||||
"PK": `^\d{5}$`,
|
||||
"PY": `^\d{4}$`,
|
||||
"PH": `^\d{4}$`,
|
||||
"PL": `^\d{2}-\d{3}$`,
|
||||
"PR": `^00[679]\d{2}([ \-]\d{4})?$`,
|
||||
"RO": `^\d{6}$`,
|
||||
"RU": `^\d{6}$`,
|
||||
"SM": `^4789\d$`,
|
||||
"SA": `^\d{5}$`,
|
||||
"SN": `^\d{5}$`,
|
||||
"SK": `^\d{3}[ ]?\d{2}$`,
|
||||
"SI": `^\d{4}$`,
|
||||
"ZA": `^\d{4}$`,
|
||||
"LK": `^\d{5}$`,
|
||||
"TJ": `^\d{6}$`,
|
||||
"TH": `^\d{5}$`,
|
||||
"TN": `^\d{4}$`,
|
||||
"TR": `^\d{5}$`,
|
||||
"TM": `^\d{6}$`,
|
||||
"UA": `^\d{5}$`,
|
||||
"UY": `^\d{5}$`,
|
||||
"UZ": `^\d{6}$`,
|
||||
"VA": `^00120$`,
|
||||
"VE": `^\d{4}$`,
|
||||
"ZM": `^\d{5}$`,
|
||||
"AS": `^96799$`,
|
||||
"CC": `^6799$`,
|
||||
"CK": `^\d{4}$`,
|
||||
"RS": `^\d{6}$`,
|
||||
"ME": `^8\d{4}$`,
|
||||
"CS": `^\d{5}$`,
|
||||
"YU": `^\d{5}$`,
|
||||
"CX": `^6798$`,
|
||||
"ET": `^\d{4}$`,
|
||||
"FK": `^FIQQ 1ZZ$`,
|
||||
"NF": `^2899$`,
|
||||
"FM": `^(9694[1-4])([ \-]\d{4})?$`,
|
||||
"GF": `^9[78]3\d{2}$`,
|
||||
"GN": `^\d{3}$`,
|
||||
"GP": `^9[78][01]\d{2}$`,
|
||||
"GS": `^SIQQ 1ZZ$`,
|
||||
"GU": `^969[123]\d([ \-]\d{4})?$`,
|
||||
"GW": `^\d{4}$`,
|
||||
"HM": `^\d{4}$`,
|
||||
"IQ": `^\d{5}$`,
|
||||
"KG": `^\d{6}$`,
|
||||
"LR": `^\d{4}$`,
|
||||
"LS": `^\d{3}$`,
|
||||
"MG": `^\d{3}$`,
|
||||
"MH": `^969[67]\d([ \-]\d{4})?$`,
|
||||
"MN": `^\d{6}$`,
|
||||
"MP": `^9695[012]([ \-]\d{4})?$`,
|
||||
"MQ": `^9[78]2\d{2}$`,
|
||||
"NC": `^988\d{2}$`,
|
||||
"NE": `^\d{4}$`,
|
||||
"VI": `^008(([0-4]\d)|(5[01]))([ \-]\d{4})?$`,
|
||||
"VN": `^[0-9]{1,6}$`,
|
||||
"PF": `^987\d{2}$`,
|
||||
"PG": `^\d{3}$`,
|
||||
"PM": `^9[78]5\d{2}$`,
|
||||
"PN": `^PCRN 1ZZ$`,
|
||||
"PW": `^96940$`,
|
||||
"RE": `^9[78]4\d{2}$`,
|
||||
"SH": `^(ASCN|STHL) 1ZZ$`,
|
||||
"SJ": `^\d{4}$`,
|
||||
"SO": `^\d{5}$`,
|
||||
"SZ": `^[HLMS]\d{3}$`,
|
||||
"TC": `^TKCA 1ZZ$`,
|
||||
"WF": `^986\d{2}$`,
|
||||
"XK": `^\d{5}$`,
|
||||
"YT": `^976\d{2}$`,
|
||||
}
|
||||
|
||||
var postCodeRegexDict = map[string]*regexp.Regexp{}
|
||||
|
||||
func init() {
|
||||
for countryCode, pattern := range postCodePatternDict {
|
||||
postCodeRegexDict[countryCode] = regexp.MustCompile(pattern)
|
||||
}
|
||||
}
|
||||
+55
-11
@@ -10,7 +10,7 @@ const (
|
||||
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})$"
|
||||
hexColorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
|
||||
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*\\)$"
|
||||
@@ -19,8 +19,10 @@ const (
|
||||
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})$"
|
||||
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}$"
|
||||
@@ -29,6 +31,17 @@ 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 = "^[A-HJKMNP-TV-Z0-9]{26}$"
|
||||
md4RegexString = "^[0-9a-f]{32}$"
|
||||
md5RegexString = "^[0-9a-f]{32}$"
|
||||
sha256RegexString = "^[0-9a-f]{64}$"
|
||||
sha384RegexString = "^[0-9a-f]{96}$"
|
||||
sha512RegexString = "^[0-9a-f]{128}$"
|
||||
ripemd128RegexString = "^[0-9a-f]{32}$"
|
||||
ripemd160RegexString = "^[0-9a-f]{40}$"
|
||||
tiger128RegexString = "^[0-9a-f]{32}$"
|
||||
tiger160RegexString = "^[0-9a-f]{40}$"
|
||||
tiger192RegexString = "^[0-9a-f]{48}$"
|
||||
aSCIIRegexString = "^[\x00-\x7F]*$"
|
||||
printableASCIIRegexString = "^[\x20-\x7E]*$"
|
||||
multibyteRegexString = "[^\x00-\x7F]"
|
||||
@@ -36,19 +49,29 @@ const (
|
||||
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
|
||||
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})`
|
||||
uRLEncodedRegexString = `^(?:[^%]|%[0-9A-Fa-f]{2})*$`
|
||||
hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(>)|(<)|(")|(&)+[;]?`
|
||||
hTMLRegexString = `<[/]?([a-zA-Z]+).*?>`
|
||||
jWTRegexString = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$"
|
||||
splitParamsRegexString = `'[^']*'|\S+`
|
||||
bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
|
||||
semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/
|
||||
dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$"
|
||||
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 (
|
||||
@@ -59,7 +82,7 @@ var (
|
||||
numericRegex = regexp.MustCompile(numericRegexString)
|
||||
numberRegex = regexp.MustCompile(numberRegexString)
|
||||
hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString)
|
||||
hexcolorRegex = regexp.MustCompile(hexcolorRegexString)
|
||||
hexColorRegex = regexp.MustCompile(hexColorRegexString)
|
||||
rgbRegex = regexp.MustCompile(rgbRegexString)
|
||||
rgbaRegex = regexp.MustCompile(rgbaRegexString)
|
||||
hslRegex = regexp.MustCompile(hslRegexString)
|
||||
@@ -68,8 +91,10 @@ var (
|
||||
emailRegex = regexp.MustCompile(emailRegexString)
|
||||
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)
|
||||
@@ -78,6 +103,17 @@ var (
|
||||
uUID4RFC4122Regex = regexp.MustCompile(uUID4RFC4122RegexString)
|
||||
uUID5RFC4122Regex = regexp.MustCompile(uUID5RFC4122RegexString)
|
||||
uUIDRFC4122Regex = regexp.MustCompile(uUIDRFC4122RegexString)
|
||||
uLIDRegex = regexp.MustCompile(uLIDRegexString)
|
||||
md4Regex = regexp.MustCompile(md4RegexString)
|
||||
md5Regex = regexp.MustCompile(md5RegexString)
|
||||
sha256Regex = regexp.MustCompile(sha256RegexString)
|
||||
sha384Regex = regexp.MustCompile(sha384RegexString)
|
||||
sha512Regex = regexp.MustCompile(sha512RegexString)
|
||||
ripemd128Regex = regexp.MustCompile(ripemd128RegexString)
|
||||
ripemd160Regex = regexp.MustCompile(ripemd160RegexString)
|
||||
tiger128Regex = regexp.MustCompile(tiger128RegexString)
|
||||
tiger160Regex = regexp.MustCompile(tiger160RegexString)
|
||||
tiger192Regex = regexp.MustCompile(tiger192RegexString)
|
||||
aSCIIRegex = regexp.MustCompile(aSCIIRegexString)
|
||||
printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString)
|
||||
multibyteRegex = regexp.MustCompile(multibyteRegexString)
|
||||
@@ -92,10 +128,18 @@ var (
|
||||
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)
|
||||
jWTRegex = regexp.MustCompile(jWTRegexString)
|
||||
splitParamsRegex = regexp.MustCompile(splitParamsRegexString)
|
||||
bicRegex = regexp.MustCompile(bicRegexString)
|
||||
semverRegex = regexp.MustCompile(semverRegexString)
|
||||
dnsRegexRFC1035Label = regexp.MustCompile(dnsRegexStringRFC1035Label)
|
||||
cveRegex = regexp.MustCompile(cveRegexString)
|
||||
mongodbRegex = regexp.MustCompile(mongodbRegexString)
|
||||
cronRegex = regexp.MustCompile(cronRegexString)
|
||||
spicedbIDRegex = regexp.MustCompile(spicedbIDRegexString)
|
||||
spicedbPermissionRegex = regexp.MustCompile(spicedbPermissionRegexString)
|
||||
spicedbTypeRegex = regexp.MustCompile(spicedbTypeRegexString)
|
||||
)
|
||||
|
||||
+9
-9
@@ -23,18 +23,18 @@ func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx {
|
||||
// to validate a struct
|
||||
type StructLevel interface {
|
||||
|
||||
// returns the main validation object, in case one wants to call validations internally.
|
||||
// Validator 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 returns the top level struct, if any
|
||||
Top() reflect.Value
|
||||
|
||||
// returns the current fields parent struct, if any
|
||||
// Parent returns the current fields parent struct, if any
|
||||
Parent() reflect.Value
|
||||
|
||||
// returns the current struct.
|
||||
// Current returns the current struct.
|
||||
Current() reflect.Value
|
||||
|
||||
// ExtractType gets the actual underlying type of field value.
|
||||
@@ -42,7 +42,7 @@ type StructLevel interface {
|
||||
// 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
|
||||
// ReportError reports an error just by passing the field and tag information
|
||||
//
|
||||
// NOTES:
|
||||
//
|
||||
@@ -54,7 +54,7 @@ type StructLevel interface {
|
||||
// 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
|
||||
// ReportValidationErrors reports an error just by passing ValidationErrors
|
||||
//
|
||||
// NOTES:
|
||||
//
|
||||
@@ -62,7 +62,7 @@ type StructLevel interface {
|
||||
// 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
|
||||
// at a level lower the current field depth
|
||||
ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors)
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ var _ StructLevel = new(validate)
|
||||
// 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.
|
||||
// should not be relied upon for an accurate value otherwise.
|
||||
func (v *validate) Top() reflect.Value {
|
||||
return v.top
|
||||
}
|
||||
@@ -85,7 +85,7 @@ func (v *validate) Top() reflect.Value {
|
||||
// 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.
|
||||
// should not be relied upon for an accurate value otherwise.
|
||||
func (v *validate) Parent() reflect.Value {
|
||||
return v.slflParent
|
||||
}
|
||||
|
||||
+76
-56
@@ -10,13 +10,13 @@ import (
|
||||
|
||||
"github.com/go-playground/locales"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
|
||||
"github.com/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
|
||||
@@ -29,10 +29,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
translation: "{0} is a required field",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
tag: "required_if",
|
||||
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
|
||||
}
|
||||
@@ -61,10 +65,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
},
|
||||
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
|
||||
|
||||
var err error
|
||||
var t string
|
||||
|
||||
@@ -123,7 +125,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
{
|
||||
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
|
||||
}
|
||||
@@ -152,10 +153,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
},
|
||||
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
|
||||
|
||||
var err error
|
||||
var t string
|
||||
|
||||
@@ -214,7 +213,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
{
|
||||
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
|
||||
}
|
||||
@@ -243,10 +241,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
},
|
||||
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
|
||||
|
||||
var err error
|
||||
var t string
|
||||
|
||||
@@ -307,7 +303,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -322,7 +317,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -335,7 +329,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
{
|
||||
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
|
||||
}
|
||||
@@ -369,10 +362,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
},
|
||||
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
|
||||
|
||||
var err error
|
||||
var t string
|
||||
var f64 float64
|
||||
@@ -380,7 +371,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
var kind reflect.Kind
|
||||
|
||||
fn := func() (err error) {
|
||||
|
||||
if idx := strings.Index(fe.Param(), "."); idx != -1 {
|
||||
digits = uint64(len(fe.Param()[idx+1:]))
|
||||
}
|
||||
@@ -456,7 +446,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
{
|
||||
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
|
||||
}
|
||||
@@ -492,7 +481,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
return
|
||||
},
|
||||
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
|
||||
|
||||
var err error
|
||||
var t string
|
||||
var f64 float64
|
||||
@@ -500,7 +488,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
var kind reflect.Kind
|
||||
|
||||
fn := func() (err error) {
|
||||
|
||||
if idx := strings.Index(fe.Param(), "."); idx != -1 {
|
||||
digits = uint64(len(fe.Param()[idx+1:]))
|
||||
}
|
||||
@@ -576,7 +563,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
{
|
||||
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
|
||||
}
|
||||
@@ -612,7 +598,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
return
|
||||
},
|
||||
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
|
||||
|
||||
var err error
|
||||
var t string
|
||||
var f64 float64
|
||||
@@ -620,7 +605,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
var kind reflect.Kind
|
||||
|
||||
fn := func() (err error) {
|
||||
|
||||
if idx := strings.Index(fe.Param(), "."); idx != -1 {
|
||||
digits = uint64(len(fe.Param()[idx+1:]))
|
||||
}
|
||||
@@ -696,7 +680,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
{
|
||||
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
|
||||
}
|
||||
@@ -732,7 +715,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
return
|
||||
},
|
||||
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
|
||||
|
||||
var err error
|
||||
var t string
|
||||
var f64 float64
|
||||
@@ -740,7 +722,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
var kind reflect.Kind
|
||||
|
||||
fn := func() (err error) {
|
||||
|
||||
if idx := strings.Index(fe.Param(), "."); idx != -1 {
|
||||
digits = uint64(len(fe.Param()[idx+1:]))
|
||||
}
|
||||
@@ -818,7 +799,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -833,7 +813,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -848,7 +827,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -863,7 +841,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -878,7 +855,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -893,7 +869,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -908,7 +883,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -923,7 +897,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -938,7 +911,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -953,7 +925,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -968,7 +939,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -983,7 +953,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -1073,7 +1042,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -1088,7 +1056,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -1103,7 +1070,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -1118,7 +1084,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -1133,7 +1098,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -1158,6 +1122,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
translation: "{0} must be a valid ISBN-13 number",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
tag: "issn",
|
||||
translation: "{0} must be a valid ISSN number",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
tag: "uuid",
|
||||
translation: "{0} must be a valid UUID",
|
||||
@@ -1178,6 +1147,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
translation: "{0} must be a valid version 5 UUID",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
tag: "ulid",
|
||||
translation: "{0} must be a valid ULID",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
tag: "ascii",
|
||||
translation: "{0} must contain only ascii characters",
|
||||
@@ -1298,6 +1272,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
translation: "{0} must contain a valid MAC address",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
tag: "fqdn",
|
||||
translation: "{0} must be a valid FQDN",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
tag: "unique",
|
||||
translation: "{0} must contain unique values",
|
||||
@@ -1308,6 +1287,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
translation: "{0} must be a valid color",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
tag: "cron",
|
||||
translation: "{0} must be a valid cron expression",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
tag: "oneof",
|
||||
translation: "{0} must be one of [{1}]",
|
||||
@@ -1325,8 +1309,13 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
tag: "json",
|
||||
translation: "{0} must be a valid json string",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
tag: "jwt",
|
||||
translation: "{0} must be a valid jwt string",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
tag: "lowercase",
|
||||
translation: "{0} must be a lowercase string",
|
||||
override: false,
|
||||
@@ -1341,7 +1330,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
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)
|
||||
@@ -1351,22 +1339,59 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
return t
|
||||
},
|
||||
},
|
||||
{
|
||||
tag: "postcode_iso3166_alpha2",
|
||||
translation: "{0} does not match postcode format of {1} country",
|
||||
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: "postcode_iso3166_alpha2_field",
|
||||
translation: "{0} does not match postcode format of country in {1} field",
|
||||
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: "boolean",
|
||||
translation: "{0} must be a valid boolean value",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
tag: "image",
|
||||
translation: "{0} must be a valid image",
|
||||
override: false,
|
||||
},
|
||||
{
|
||||
tag: "cve",
|
||||
translation: "{0} must be a valid cve identifier",
|
||||
override: false,
|
||||
},
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -1380,21 +1405,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
+28
-5
@@ -1,7 +1,9 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -82,7 +84,7 @@ BEGIN:
|
||||
fld := namespace
|
||||
var ns string
|
||||
|
||||
if typ != timeType {
|
||||
if !typ.ConvertibleTo(timeType) {
|
||||
|
||||
idx := strings.Index(namespace, namespaceSeparator)
|
||||
|
||||
@@ -234,7 +236,7 @@ func asInt(param string) int64 {
|
||||
func asIntFromTimeDuration(param string) int64 {
|
||||
d, err := time.ParseDuration(param)
|
||||
if err != nil {
|
||||
// attempt parsing as an an integer assuming nanosecond precision
|
||||
// attempt parsing as an integer assuming nanosecond precision
|
||||
return asInt(param)
|
||||
}
|
||||
return int64(d)
|
||||
@@ -261,13 +263,19 @@ func asUint(param string) uint64 {
|
||||
return i
|
||||
}
|
||||
|
||||
// asFloat returns the parameter as a float64
|
||||
// asFloat64 returns the parameter as a float64
|
||||
// or panics if it can't convert
|
||||
func asFloat(param string) float64 {
|
||||
|
||||
func asFloat64(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
|
||||
}
|
||||
|
||||
@@ -286,3 +294,18 @@ 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+79
-70
@@ -74,7 +74,7 @@ func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, cur
|
||||
}
|
||||
}
|
||||
|
||||
v.traverseField(ctx, parent, current.Field(f.idx), ns, structNs, f, f.cTags)
|
||||
v.traverseField(ctx, current, current.Field(f.idx), ns, structNs, f, f.cTags)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,8 @@ 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:
|
||||
|
||||
@@ -110,6 +112,10 @@ 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...))
|
||||
@@ -160,86 +166,61 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if kind == reflect.Invalid {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !ct.hasTag {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
typ = current.Type()
|
||||
|
||||
OUTER:
|
||||
for {
|
||||
if ct == nil {
|
||||
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)
|
||||
}
|
||||
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:
|
||||
|
||||
@@ -256,6 +237,26 @@ 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
|
||||
|
||||
@@ -355,6 +356,10 @@ OUTER:
|
||||
v.ct = ct
|
||||
|
||||
if ct.fn(ctx, v) {
|
||||
if ct.isBlockEnd {
|
||||
ct = ct.next
|
||||
continue OUTER
|
||||
}
|
||||
|
||||
// drain rest of the 'or' values, then continue or leave
|
||||
for {
|
||||
@@ -362,12 +367,17 @@ OUTER:
|
||||
ct = ct.next
|
||||
|
||||
if ct == nil {
|
||||
return
|
||||
continue OUTER
|
||||
}
|
||||
|
||||
if ct.typeof != typeOr {
|
||||
continue OUTER
|
||||
}
|
||||
|
||||
if ct.isBlockEnd {
|
||||
ct = ct.next
|
||||
continue OUTER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,7 +453,6 @@ OUTER:
|
||||
v.ct = ct
|
||||
|
||||
if !ct.fn(ctx, v) {
|
||||
|
||||
v.str1 = string(append(ns, cf.altName...))
|
||||
|
||||
if v.v.hasTagNameFunc {
|
||||
|
||||
+122
-32
@@ -22,6 +22,7 @@ const (
|
||||
structOnlyTag = "structonly"
|
||||
noStructLevelTag = "nostructlevel"
|
||||
omitempty = "omitempty"
|
||||
omitnil = "omitnil"
|
||||
isdefault = "isdefault"
|
||||
requiredWithoutAllTag = "required_without_all"
|
||||
requiredWithoutTag = "required_without"
|
||||
@@ -29,6 +30,13 @@ const (
|
||||
requiredWithAllTag = "required_with_all"
|
||||
requiredIfTag = "required_if"
|
||||
requiredUnlessTag = "required_unless"
|
||||
skipUnlessTag = "skip_unless"
|
||||
excludedWithoutAllTag = "excluded_without_all"
|
||||
excludedWithoutTag = "excluded_without"
|
||||
excludedWithTag = "excluded_with"
|
||||
excludedWithAllTag = "excluded_with_all"
|
||||
excludedIfTag = "excluded_if"
|
||||
excludedUnlessTag = "excluded_unless"
|
||||
skipValidationTag = "-"
|
||||
diveTag = "dive"
|
||||
keysTag = "keys"
|
||||
@@ -46,12 +54,14 @@ var (
|
||||
timeDurationType = reflect.TypeOf(time.Duration(0))
|
||||
timeType = reflect.TypeOf(time.Time{})
|
||||
|
||||
byteSliceType = reflect.TypeOf([]byte{})
|
||||
|
||||
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
|
||||
// returning true results in the field being filtered/skipped from
|
||||
// validation
|
||||
type FilterFunc func(ns []byte) bool
|
||||
|
||||
@@ -70,22 +80,28 @@ type internalValidationFuncWrapper struct {
|
||||
|
||||
// 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
|
||||
transTagFunc map[ut.Translator]map[string]TranslationFunc // map[<locale>]map[<tag>]TranslationFunc
|
||||
tagCache *tagCache
|
||||
structCache *structCache
|
||||
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
|
||||
}
|
||||
|
||||
// New returns a new instance of 'validate' with sane defaults.
|
||||
func New() *Validate {
|
||||
// Validate is designed to be thread-safe and used as a singleton instance.
|
||||
// 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 {
|
||||
|
||||
tc := new(tagCache)
|
||||
tc.m.Store(make(map[string]*cTag))
|
||||
@@ -111,7 +127,9 @@ func New() *Validate {
|
||||
|
||||
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:
|
||||
case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag,
|
||||
excludedIfTag, excludedUnlessTag, excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag,
|
||||
skipUnlessTag:
|
||||
_ = v.registerValidation(k, wrapFunc(val), true, true)
|
||||
default:
|
||||
// no need to error check here, baked in will always be valid
|
||||
@@ -130,6 +148,9 @@ func New() *Validate {
|
||||
},
|
||||
}
|
||||
|
||||
for _, o := range options {
|
||||
o(v)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -138,17 +159,54 @@ func (v *Validate) SetTagName(name string) {
|
||||
v.tagName = name
|
||||
}
|
||||
|
||||
// ValidateMapCtx validates a map using a map of validation rules and allows passing of contextual
|
||||
// validation information via context.Context.
|
||||
func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{} {
|
||||
errs := make(map[string]interface{})
|
||||
for field, rule := range rules {
|
||||
if ruleObj, ok := rule.(map[string]interface{}); ok {
|
||||
if dataObj, ok := data[field].(map[string]interface{}); ok {
|
||||
err := v.ValidateMapCtx(ctx, dataObj, ruleObj)
|
||||
if len(err) > 0 {
|
||||
errs[field] = err
|
||||
}
|
||||
} else if dataObjs, ok := data[field].([]map[string]interface{}); ok {
|
||||
for _, obj := range dataObjs {
|
||||
err := v.ValidateMapCtx(ctx, obj, ruleObj)
|
||||
if len(err) > 0 {
|
||||
errs[field] = err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errs[field] = errors.New("The field: '" + field + "' is not a map to dive")
|
||||
}
|
||||
} else if ruleStr, ok := rule.(string); ok {
|
||||
err := v.VarCtx(ctx, data[field], ruleStr)
|
||||
if err != nil {
|
||||
errs[field] = err
|
||||
}
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// ValidateMap validates map data from a map of tags
|
||||
func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]interface{}) map[string]interface{} {
|
||||
return v.ValidateMapCtx(context.Background(), data, rules)
|
||||
}
|
||||
|
||||
// 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
|
||||
// })
|
||||
// validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
|
||||
// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
|
||||
// // skip if tag key says it should be ignored
|
||||
// if name == "-" {
|
||||
// return ""
|
||||
// }
|
||||
// return name
|
||||
// })
|
||||
func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) {
|
||||
v.tagNameFunc = fn
|
||||
v.hasTagNameFunc = true
|
||||
@@ -175,11 +233,11 @@ func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationE
|
||||
|
||||
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")
|
||||
return errors.New("function Key cannot be empty")
|
||||
}
|
||||
|
||||
if fn == nil {
|
||||
return errors.New("Function cannot be empty")
|
||||
return errors.New("function cannot be empty")
|
||||
}
|
||||
|
||||
_, ok := restrictedTags[tag]
|
||||
@@ -235,6 +293,34 @@ func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...i
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterStructValidationMapRules registers validate map rules.
|
||||
// Be aware that map validation rules supersede those defined on a/the struct if present.
|
||||
//
|
||||
// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
|
||||
func (v *Validate) RegisterStructValidationMapRules(rules map[string]string, types ...interface{}) {
|
||||
if v.rules == nil {
|
||||
v.rules = make(map[reflect.Type]map[string]string)
|
||||
}
|
||||
|
||||
deepCopyRules := make(map[string]string)
|
||||
for i, rule := range rules {
|
||||
deepCopyRules[i] = rule
|
||||
}
|
||||
|
||||
for _, t := range types {
|
||||
typ := reflect.TypeOf(t)
|
||||
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
}
|
||||
|
||||
if typ.Kind() != reflect.Struct {
|
||||
continue
|
||||
}
|
||||
v.rules[typ] = deepCopyRules
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -295,7 +381,7 @@ func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) {
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
if val.Kind() != reflect.Struct || val.Type() == timeType {
|
||||
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
|
||||
return &InvalidValidationError{Type: reflect.TypeOf(s)}
|
||||
}
|
||||
|
||||
@@ -340,7 +426,7 @@ func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{}, fn Filt
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
if val.Kind() != reflect.Struct || val.Type() == timeType {
|
||||
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
|
||||
return &InvalidValidationError{Type: reflect.TypeOf(s)}
|
||||
}
|
||||
|
||||
@@ -374,7 +460,7 @@ func (v *Validate) StructPartial(s interface{}, fields ...string) error {
|
||||
}
|
||||
|
||||
// StructPartialCtx validates the fields passed in only, ignoring all others and allows passing of contextual
|
||||
// validation validation information via context.Context
|
||||
// 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
|
||||
//
|
||||
@@ -388,7 +474,7 @@ func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields .
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
if val.Kind() != reflect.Struct || val.Type() == timeType {
|
||||
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
|
||||
return &InvalidValidationError{Type: reflect.TypeOf(s)}
|
||||
}
|
||||
|
||||
@@ -409,7 +495,10 @@ func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields .
|
||||
if len(flds) > 0 {
|
||||
|
||||
vd.misc = append(vd.misc[0:0], name...)
|
||||
vd.misc = append(vd.misc, '.')
|
||||
// Don't append empty name for unnamed structs
|
||||
if len(vd.misc) != 0 {
|
||||
vd.misc = append(vd.misc, '.')
|
||||
}
|
||||
|
||||
for _, s := range flds {
|
||||
|
||||
@@ -461,7 +550,7 @@ func (v *Validate) StructExcept(s interface{}, fields ...string) error {
|
||||
}
|
||||
|
||||
// StructExceptCtx validates all fields except the ones passed in and allows passing of contextual
|
||||
// validation validation information via context.Context
|
||||
// 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
|
||||
//
|
||||
@@ -475,7 +564,7 @@ func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ..
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
if val.Kind() != reflect.Struct || val.Type() == timeType {
|
||||
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
|
||||
return &InvalidValidationError{Type: reflect.TypeOf(s)}
|
||||
}
|
||||
|
||||
@@ -533,7 +622,7 @@ func (v *Validate) Var(field interface{}, tag string) error {
|
||||
}
|
||||
|
||||
// VarCtx validates a single variable using tag style validation and allows passing of contextual
|
||||
// validation validation information via context.Context.
|
||||
// validation information via context.Context.
|
||||
// eg.
|
||||
// var i int
|
||||
// validate.Var(i, "gt=1,lt=10")
|
||||
@@ -552,6 +641,7 @@ func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (e
|
||||
}
|
||||
|
||||
ctag := v.fetchCacheTag(tag)
|
||||
|
||||
val := reflect.ValueOf(field)
|
||||
vd := v.pool.Get().(*validate)
|
||||
vd.top = val
|
||||
|
||||
+2
-1
@@ -8,4 +8,5 @@
|
||||
*.out
|
||||
*.txt
|
||||
|
||||
vendor/
|
||||
vendor/
|
||||
/removecomments
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
- tip
|
||||
|
||||
before_install:
|
||||
- go get -t -v ./...
|
||||
|
||||
script:
|
||||
- go test -race -coverprofile=coverage.txt -covermode=atomic
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
+27
-1
@@ -1,4 +1,4 @@
|
||||
[](https://travis-ci.org/leodido/go-urn) [](https://codecov.io/gh/leodido/go-urn) [](https://godoc.org/github.com/leodido/go-urn)
|
||||
[](https://app.circleci.com/pipelines/github/leodido/go-urn) [](https://codecov.io/gh/leodido/go-urn) [](https://godoc.org/github.com/leodido/go-urn)
|
||||
|
||||
**A parser for URNs**.
|
||||
|
||||
@@ -52,4 +52,30 @@ no/19/urn:UrN:NSS__________________________________/-4 20000000 399 ns
|
||||
|
||||
---
|
||||
|
||||
## Example
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leodido/go-urn"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var uid = "URN:foo:a123,456"
|
||||
|
||||
u, ok := urn.Parse([]byte(uid))
|
||||
if !ok {
|
||||
panic("error parsing urn")
|
||||
}
|
||||
|
||||
fmt.Println(u.ID)
|
||||
fmt.Println(u.SS)
|
||||
|
||||
// Output:
|
||||
// foo
|
||||
// a123,456
|
||||
}
|
||||
```
|
||||
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
-3
@@ -61,11 +61,9 @@ func (m *machine) Parse(input []byte) (*URN, error) {
|
||||
m.err = nil
|
||||
m.tolower = []int{}
|
||||
output := &URN{}
|
||||
|
||||
{
|
||||
m.cs = start
|
||||
}
|
||||
|
||||
{
|
||||
if (m.p) == (m.pe) {
|
||||
goto _testEof
|
||||
@@ -1674,7 +1672,6 @@ func (m *machine) Parse(input []byte) (*URN, error) {
|
||||
{
|
||||
goto st46
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
-13
@@ -1,18 +1,37 @@
|
||||
SHELL := /bin/bash
|
||||
RAGEL := ragel
|
||||
GOFMT := go fmt
|
||||
|
||||
export GO_TEST=env GOTRACEBACK=all go test $(GO_ARGS)
|
||||
|
||||
.PHONY: build
|
||||
build: machine.go
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -rf docs
|
||||
@rm -f machine.go
|
||||
|
||||
.PHONY: images
|
||||
images: docs/urn.png
|
||||
|
||||
.PHONY: removecomments
|
||||
removecomments:
|
||||
@cd ./tools/removecomments; go build -o ../../removecomments .
|
||||
|
||||
machine.go: machine.go.rl
|
||||
ragel -Z -G2 -e -o $@ $<
|
||||
@sed -i '/^\/\/line/d' $@
|
||||
@$(MAKE) -s file=$@ snake2camel
|
||||
@gofmt -w -s $@
|
||||
|
||||
machine.go: removecomments
|
||||
|
||||
machine.go:
|
||||
$(RAGEL) -Z -G2 -e -o $@ $<
|
||||
@./removecomments $@
|
||||
$(MAKE) -s file=$@ snake2camel
|
||||
$(GOFMT) $@
|
||||
|
||||
docs/urn.dot: machine.go.rl
|
||||
@mkdir -p docs
|
||||
ragel -Z -e -Vp $< -o $@
|
||||
$(RAGEL) -Z -e -Vp $< -o $@
|
||||
|
||||
docs/urn.png: docs/urn.dot
|
||||
dot $< -Tpng -o $@
|
||||
@@ -22,13 +41,8 @@ bench: *_test.go machine.go
|
||||
go test -bench=. -benchmem -benchtime=5s ./...
|
||||
|
||||
.PHONY: tests
|
||||
tests: *_test.go machine.go
|
||||
go test -race -timeout 10s -coverprofile=coverage.out -covermode=atomic -v ./...
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -rf docs
|
||||
@rm -f machine.go
|
||||
tests: *_test.go
|
||||
$(GO_TEST) ./...
|
||||
|
||||
.PHONY: snake2camel
|
||||
snake2camel:
|
||||
@@ -36,4 +50,4 @@ snake2camel:
|
||||
while ( match($$0, /(.*)([a-z]+[0-9]*)_([a-zA-Z0-9])(.*)/, cap) ) \
|
||||
$$0 = cap[1] cap[2] toupper(cap[3]) cap[4]; \
|
||||
print \
|
||||
}' $(file)
|
||||
}' $(file)
|
||||
|
||||
+23
@@ -1,9 +1,13 @@
|
||||
package urn
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const errInvalidURN = "invalid URN: %s"
|
||||
|
||||
// URN represents an Uniform Resource Name.
|
||||
//
|
||||
// The general form represented is:
|
||||
@@ -61,3 +65,22 @@ func Parse(u []byte) (*URN, bool) {
|
||||
|
||||
return urn, true
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the URN to JSON string form (e.g. `"urn:oid:1.2.3.4"`).
|
||||
func (u URN) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(u.String())
|
||||
}
|
||||
|
||||
// MarshalJSON unmarshals a URN from JSON string form (e.g. `"urn:oid:1.2.3.4"`).
|
||||
func (u *URN) UnmarshalJSON(bytes []byte) error {
|
||||
var str string
|
||||
if err := json.Unmarshal(bytes, &str); err != nil {
|
||||
return err
|
||||
}
|
||||
if value, ok := Parse([]byte(str)); !ok {
|
||||
return fmt.Errorf(errInvalidURN, str)
|
||||
} else {
|
||||
*u = *value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user