@@ -17,6 +17,7 @@ package schema
1717
1818import (
1919 "encoding/json"
20+ "fmt"
2021 "regexp"
2122
2223 "github.com/arduino/go-paths-helper"
@@ -76,10 +77,10 @@ func validationErrorMatch(
7677 logrus .Tracef ("Checking instance pointer: %s match with regexp: %s" , validationError .InstancePtr , instancePointerRegexp )
7778 if instancePointerRegexp .MatchString (validationError .InstancePtr ) {
7879 logrus .Tracef ("Matched!" )
79- logrus . Tracef ( "Checking schema pointer: %s match with regexp: %s" , validationError . SchemaPtr , schemaPointerRegexp )
80- if schemaPointerRegexp . MatchString ( validationError . SchemaPtr ) {
80+ matchedSchemaPointer := validationErrorSchemaPointerMatch ( schemaPointerRegexp , validationError , schemasPath )
81+ if matchedSchemaPointer != "" {
8182 logrus .Tracef ("Matched!" )
82- if validationErrorSchemaPointerValueMatch (schemaPointerValueRegexp , validationError , schemasPath ) {
83+ if validationErrorSchemaPointerValueMatch (schemaPointerValueRegexp , validationError . SchemaURL , matchedSchemaPointer , schemasPath ) {
8384 logrus .Tracef ("Matched!" )
8485 logrus .Tracef ("Checking failure context: %v match with regexp: %s" , validationError .Context , failureContextRegexp )
8586 if validationErrorContextMatch (failureContextRegexp , validationError ) {
@@ -107,14 +108,67 @@ func validationErrorMatch(
107108 return false
108109}
109110
111+ // validationErrorSchemaPointerMatch matches the JSON schema pointer related to the validation failure against a regular expression.
112+ func validationErrorSchemaPointerMatch (
113+ schemaPointerRegexp * regexp.Regexp ,
114+ validationError * jsonschema.ValidationError ,
115+ schemasPath * paths.Path ,
116+ ) string {
117+ logrus .Tracef ("Checking schema pointer: %s match with regexp: %s" , validationError .SchemaPtr , schemaPointerRegexp )
118+ if schemaPointerRegexp .MatchString (validationError .SchemaPtr ) {
119+ return validationError .SchemaPtr
120+ }
121+
122+ // The schema validator does not provide full pointer past logic inversion keywords to the lowest level keywords related to the validation error cause.
123+ // Therefore the sub-keywords must be checked for matches in order to be able to interpret the exact cause of the failure.
124+ if regexp .MustCompile ("(/not)|(/oneOf)$" ).MatchString (validationError .SchemaPtr ) {
125+ return validationErrorSchemaSubPointerMatch (schemaPointerRegexp , validationError .SchemaPtr , validationErrorSchemaPointerValue (validationError , schemasPath ))
126+ }
127+
128+ return ""
129+ }
130+
131+ // validationErrorSchemaSubPointerMatch recursively checks JSON pointers of all keywords under the parent pointer for match against a regular expression.
132+ // The matching JSON pointer is returned.
133+ func validationErrorSchemaSubPointerMatch (schemaPointerRegexp * regexp.Regexp , parentPointer string , pointerValueObject interface {}) string {
134+ // Recurse through iterable objects.
135+ switch assertedObject := pointerValueObject .(type ) {
136+ case []interface {}:
137+ for index , element := range assertedObject {
138+ // Append index to JSON pointer and check for match.
139+ matchingPointer := validationErrorSchemaSubPointerMatch (schemaPointerRegexp , fmt .Sprintf ("%s/%d" , parentPointer , index ), element )
140+ if matchingPointer != "" {
141+ return matchingPointer
142+ }
143+ }
144+ case map [string ]interface {}:
145+ for key := range assertedObject {
146+ // Append key to JSON pointer and check for match.
147+ matchingPointer := validationErrorSchemaSubPointerMatch (schemaPointerRegexp , parentPointer + "/" + key , assertedObject [key ])
148+ if matchingPointer != "" {
149+ return matchingPointer
150+ }
151+ // TODO: Follow references. For now, the schema code must be written so that the problematic keywords are after the reference.
152+ }
153+ }
154+
155+ // pointerValueObject is not further iterable. Check for match against the parent JSON pointer.
156+ logrus .Tracef ("Checking schema pointer: %s match with regexp: %s" , parentPointer , schemaPointerRegexp )
157+ if schemaPointerRegexp .MatchString (parentPointer ) {
158+ return parentPointer
159+ }
160+ return ""
161+ }
162+
110163// validationErrorSchemaPointerValueMatch marshalls the data in the schema at the given JSON pointer and returns whether
111164// it matches against the given regular expression.
112165func validationErrorSchemaPointerValueMatch (
113166 schemaPointerValueRegexp * regexp.Regexp ,
114- validationError * jsonschema.ValidationError ,
167+ schemaURL ,
168+ schemaPointer string ,
115169 schemasPath * paths.Path ,
116170) bool {
117- marshalledSchemaPointerValue , err := json .Marshal (schemaPointerValue (validationError , schemasPath ))
171+ marshalledSchemaPointerValue , err := json .Marshal (schemaPointerValue (schemaURL , schemaPointer , schemasPath ))
118172 logrus .Tracef ("Checking schema pointer value: %s match with regexp: %s" , marshalledSchemaPointerValue , schemaPointerValueRegexp )
119173 if err != nil {
120174 panic (err )
0 commit comments