11package jsonschema
22
33import (
4+ // "encoding/json"
45 "fmt"
56 "net"
7+ "net/url"
68 "regexp"
9+ "strconv"
710 "strings"
811 "time"
912)
1013
1114const (
12- email string = "^(((([a-zA-Z]|\\ d|[!#\\ $%&'\\ *\\ +\\ -\\ /=\\ ?\\ ^_`{\\ |}~]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])+(\\ .([a-zA-Z]|\\ d|[!#\\ $%&'\\ *\\ +\\ -\\ /=\\ ?\\ ^_`{\\ |}~]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])+)*)|((\\ x22)((((\\ x20|\\ x09)*(\\ x0d\\ x0a))?(\\ x20|\\ x09)+)?(([\\ x01-\\ x08\\ x0b\\ x0c\\ x0e-\\ x1f\\ x7f]|\\ x21|[\\ x23-\\ x5b]|[\\ x5d-\\ x7e]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])|(\\ ([\\ x01-\\ x09\\ x0b\\ x0c\\ x0d-\\ x7f]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}]))))*(((\\ x20|\\ x09)*(\\ x0d\\ x0a))?(\\ x20|\\ x09)+)?(\\ x22)))@((([a-zA-Z]|\\ d|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])|(([a-zA-Z]|\\ d|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])([a-zA-Z]|\\ d|-|\\ .|_|~|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])*([a-zA-Z]|\\ d|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])))\\ .)+(([a-zA-Z]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])|(([a-zA-Z]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])([a-zA-Z]|\\ d|-|_|~|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])*([a-zA-Z]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])))\\ .?$"
13- hostname string = `^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`
15+ email string = "^(((([a-zA-Z]|\\ d|[!#\\ $%&'\\ *\\ +\\ -\\ /=\\ ?\\ ^_`{\\ |}~]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])+(\\ .([a-zA-Z]|\\ d|[!#\\ $%&'\\ *\\ +\\ -\\ /=\\ ?\\ ^_`{\\ |}~]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])+)*)|((\\ x22)((((\\ x20|\\ x09)*(\\ x0d\\ x0a))?(\\ x20|\\ x09)+)?(([\\ x01-\\ x08\\ x0b\\ x0c\\ x0e-\\ x1f\\ x7f]|\\ x21|[\\ x23-\\ x5b]|[\\ x5d-\\ x7e]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])|(\\ ([\\ x01-\\ x09\\ x0b\\ x0c\\ x0d-\\ x7f]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}]))))*(((\\ x20|\\ x09)*(\\ x0d\\ x0a))?(\\ x20|\\ x09)+)?(\\ x22)))@((([a-zA-Z]|\\ d|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])|(([a-zA-Z]|\\ d|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])([a-zA-Z]|\\ d|-|\\ .|_|~|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])*([a-zA-Z]|\\ d|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])))\\ .)+(([a-zA-Z]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])|(([a-zA-Z]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])([a-zA-Z]|\\ d|-|_|~|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])*([a-zA-Z]|[\\ x{00A0}-\\ x{D7FF}\\ x{F900}-\\ x{FDCF}\\ x{FDF0}-\\ x{FFEF}])))\\ .?$"
16+ hostname string = `^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`
17+ unescapedTilda = `\~[^01]`
18+ endingTilda = `\~$`
1419)
1520
1621var (
17- emailPattern = regexp .MustCompile (email )
18- hostnamePattern = regexp .MustCompile (hostname )
22+ emailPattern = regexp .MustCompile (email )
23+ hostnamePattern = regexp .MustCompile (hostname )
24+ unescaptedTildaPattern = regexp .MustCompile (unescapedTilda )
25+ endingTildaPattern = regexp .MustCompile (endingTilda )
1926)
2027
28+ // for json pointers
29+
2130// func FormatType(data interface{}) string {
2231// switch
2332// }
@@ -68,6 +77,10 @@ func (f format) Validate(data interface{}) error {
6877 return isValidURITemplate (str )
6978 case "uri" :
7079 return isValidURI (str )
80+ default :
81+ // TODO: should we return an error saying that we don't know that
82+ // format? or should we keep it as is (ignore, return nil)
83+ return nil
7184 }
7285 }
7386 return nil
@@ -85,8 +98,8 @@ func isValidDateTime(dateTime string) error {
8598}
8699
87100// A string instance is valid against "date" if it is a valid
88- // representation according to the "date" production derived from RFC
89- // 3339, section 5.6 [RFC3339]
101+ // representation according to the "full- date" production derived
102+ // from RFC 3339, section 5.6 [RFC3339]
90103// https://tools.ietf.org/html/rfc3339#section-5.6
91104func isValidDate (date string ) error {
92105 arbitraryTime := "T08:30:06.283185Z"
@@ -180,23 +193,68 @@ func isValidIri(iri string) error {
180193// RFC 6901, section 5 [RFC6901].
181194// https://tools.ietf.org/html/rfc6901#section-5
182195func isValidJSONPointer (jsonPointer string ) error {
196+ // if !validateEscapeChars(jsonPointer) {
197+ // return fmt.Errorf("json pointer includes unescaped characters")
198+ // }
199+ // if _, err := jsonpointer.Parse(jsonPointer); err != nil {
200+ // return fmt.Errorf("invalid json pointer: %s", err.Error())
201+ // }
202+ if len (jsonPointer ) == 0 {
203+ return nil
204+ }
205+ if jsonPointer [0 ] != '/' {
206+ return fmt .Errorf ("non-empty references must begin with a '/' character" )
207+ }
208+ str := jsonPointer [1 :]
209+ if unescaptedTildaPattern .MatchString (str ) {
210+ return fmt .Errorf ("unescaped tilda error" )
211+ }
212+ if endingTildaPattern .MatchString (str ) {
213+ return fmt .Errorf ("unescaped tilda error" )
214+ }
183215 return nil
184216}
185217
186218// A string instance is a valid against "regex" if it is a valid
219+ // regular expression according to the ECMA 262 [ecma262] regular
220+ // expression dialect. Implementations that validate formats MUST
221+ // accept at least the subset of ECMA 262 defined in the Regular
222+ // Expressions [regexInterop] section of this specification, and
223+ // SHOULD accept all valid ECMA 262 expressions.
224+ // http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
225+ // http://json-schema.org/latest/json-schema-validation.html#regexInterop
226+ // https://tools.ietf.org/html/rfc7159
187227func isValidRegex (regex string ) error {
188228 return nil
189229}
190230
191231// A string instance is a valid against "relative-json-pointer" if it
192232// is a valid Relative JSON Pointer [relative-json-pointer].
193233// https://tools.ietf.org/html/draft-handrews-relative-json-pointer-00
194- func isValidRelJSONPointer (relJsonPointer string ) error {
195- return nil
234+ func isValidRelJSONPointer (relJSONPointer string ) error {
235+ parts := strings .Split (relJSONPointer , "/" )
236+ if len (parts ) == 1 {
237+ parts = strings .Split (relJSONPointer , "#" )
238+ }
239+ if i , err := strconv .Atoi (parts [0 ]); err != nil || i < 0 {
240+ return fmt .Errorf ("RJP must begin with positive integer" )
241+ }
242+ //skip over first part
243+ str := relJSONPointer [len (parts [0 ]):]
244+ if len (str ) > 0 && str [0 ] == '#' {
245+ return nil
246+ }
247+ return isValidJSONPointer (str )
196248}
197249
198- // A string instance is a valid against "time" if it is a valid
250+ // A string instance is valid against "time" if it is a valid
251+ // representation according to the "full-time" production derived
252+ // from RFC 3339, section 5.6 [RFC3339]
253+ // https://tools.ietf.org/html/rfc3339#section-5.6
199254func isValidTime (time string ) error {
255+ arbitraryDate := "1963-06-19"
256+ dateTime := fmt .Sprintf ("%sT%s" , arbitraryDate , time )
257+ return isValidDateTime (dateTime )
200258 return nil
201259}
202260
@@ -221,5 +279,8 @@ func isValidURITemplate(uriTemplate string) error {
221279// according to [RFC3986].
222280// https://tools.ietf.org/html/rfc3986
223281func isValidURI (uri string ) error {
282+ if _ , err := url .Parse (uri ); err != nil {
283+ return fmt .Errorf ("uri incorrectly formatted: %s" , err .Error ())
284+ }
224285 return nil
225286}
0 commit comments