Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / xeipuuv / gojsonschema / schema.go
1 // Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //   http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // author           xeipuuv
16 // author-github    https://github.com/xeipuuv
17 // author-mail      xeipuuv@gmail.com
18 //
19 // repository-name  gojsonschema
20 // repository-desc  An implementation of JSON Schema, based on IETF's draft v4 - Go language.
21 //
22 // description      Defines Schema, the main entry to every subSchema.
23 //                  Contains the parsing logic and error checking.
24 //
25 // created          26-02-2013
26
27 package gojsonschema
28
29 import (
30         //      "encoding/json"
31         "errors"
32         "reflect"
33         "regexp"
34
35         "github.com/xeipuuv/gojsonreference"
36 )
37
38 var (
39         // Locale is the default locale to use
40         // Library users can overwrite with their own implementation
41         Locale locale = DefaultLocale{}
42 )
43
44 func NewSchema(l JSONLoader) (*Schema, error) {
45         return l.loadSchema()
46 }
47
48 type Schema struct {
49         documentReference gojsonreference.JsonReference
50         rootSchema        *subSchema
51         pool              *schemaPool
52         referencePool     *schemaReferencePool
53 }
54
55 func (d *Schema) parse(document interface{}) error {
56         d.rootSchema = &subSchema{property: STRING_ROOT_SCHEMA_PROPERTY}
57         return d.parseSchema(document, d.rootSchema)
58 }
59
60 func (d *Schema) SetRootSchemaName(name string) {
61         d.rootSchema.property = name
62 }
63
64 // Parses a subSchema
65 //
66 // Pretty long function ( sorry :) )... but pretty straight forward, repetitive and boring
67 // Not much magic involved here, most of the job is to validate the key names and their values,
68 // then the values are copied into subSchema struct
69 //
70 func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema) error {
71
72         if !isKind(documentNode, reflect.Map) {
73                 return errors.New(formatErrorDescription(
74                         Locale.InvalidType(),
75                         ErrorDetails{
76                                 "expected": TYPE_OBJECT,
77                                 "given":    STRING_SCHEMA,
78                         },
79                 ))
80         }
81
82         m := documentNode.(map[string]interface{})
83
84         if currentSchema == d.rootSchema {
85                 currentSchema.ref = &d.documentReference
86         }
87
88         // $subSchema
89         if existsMapKey(m, KEY_SCHEMA) {
90                 if !isKind(m[KEY_SCHEMA], reflect.String) {
91                         return errors.New(formatErrorDescription(
92                                 Locale.InvalidType(),
93                                 ErrorDetails{
94                                         "expected": TYPE_STRING,
95                                         "given":    KEY_SCHEMA,
96                                 },
97                         ))
98                 }
99                 schemaRef := m[KEY_SCHEMA].(string)
100                 schemaReference, err := gojsonreference.NewJsonReference(schemaRef)
101                 currentSchema.subSchema = &schemaReference
102                 if err != nil {
103                         return err
104                 }
105         }
106
107         // $ref
108         if existsMapKey(m, KEY_REF) && !isKind(m[KEY_REF], reflect.String) {
109                 return errors.New(formatErrorDescription(
110                         Locale.InvalidType(),
111                         ErrorDetails{
112                                 "expected": TYPE_STRING,
113                                 "given":    KEY_REF,
114                         },
115                 ))
116         }
117         if k, ok := m[KEY_REF].(string); ok {
118
119                 if sch, ok := d.referencePool.Get(currentSchema.ref.String() + k); ok {
120
121                         currentSchema.refSchema = sch
122
123                 } else {
124
125                         var err error
126                         err = d.parseReference(documentNode, currentSchema, k)
127                         if err != nil {
128                                 return err
129                         }
130
131                         return nil
132                 }
133         }
134
135         // definitions
136         if existsMapKey(m, KEY_DEFINITIONS) {
137                 if isKind(m[KEY_DEFINITIONS], reflect.Map) {
138                         currentSchema.definitions = make(map[string]*subSchema)
139                         for dk, dv := range m[KEY_DEFINITIONS].(map[string]interface{}) {
140                                 if isKind(dv, reflect.Map) {
141                                         newSchema := &subSchema{property: KEY_DEFINITIONS, parent: currentSchema, ref: currentSchema.ref}
142                                         currentSchema.definitions[dk] = newSchema
143                                         err := d.parseSchema(dv, newSchema)
144                                         if err != nil {
145                                                 return errors.New(err.Error())
146                                         }
147                                 } else {
148                                         return errors.New(formatErrorDescription(
149                                                 Locale.InvalidType(),
150                                                 ErrorDetails{
151                                                         "expected": STRING_ARRAY_OF_SCHEMAS,
152                                                         "given":    KEY_DEFINITIONS,
153                                                 },
154                                         ))
155                                 }
156                         }
157                 } else {
158                         return errors.New(formatErrorDescription(
159                                 Locale.InvalidType(),
160                                 ErrorDetails{
161                                         "expected": STRING_ARRAY_OF_SCHEMAS,
162                                         "given":    KEY_DEFINITIONS,
163                                 },
164                         ))
165                 }
166
167         }
168
169         // id
170         if existsMapKey(m, KEY_ID) && !isKind(m[KEY_ID], reflect.String) {
171                 return errors.New(formatErrorDescription(
172                         Locale.InvalidType(),
173                         ErrorDetails{
174                                 "expected": TYPE_STRING,
175                                 "given":    KEY_ID,
176                         },
177                 ))
178         }
179         if k, ok := m[KEY_ID].(string); ok {
180                 currentSchema.id = &k
181         }
182
183         // title
184         if existsMapKey(m, KEY_TITLE) && !isKind(m[KEY_TITLE], reflect.String) {
185                 return errors.New(formatErrorDescription(
186                         Locale.InvalidType(),
187                         ErrorDetails{
188                                 "expected": TYPE_STRING,
189                                 "given":    KEY_TITLE,
190                         },
191                 ))
192         }
193         if k, ok := m[KEY_TITLE].(string); ok {
194                 currentSchema.title = &k
195         }
196
197         // description
198         if existsMapKey(m, KEY_DESCRIPTION) && !isKind(m[KEY_DESCRIPTION], reflect.String) {
199                 return errors.New(formatErrorDescription(
200                         Locale.InvalidType(),
201                         ErrorDetails{
202                                 "expected": TYPE_STRING,
203                                 "given":    KEY_DESCRIPTION,
204                         },
205                 ))
206         }
207         if k, ok := m[KEY_DESCRIPTION].(string); ok {
208                 currentSchema.description = &k
209         }
210
211         // type
212         if existsMapKey(m, KEY_TYPE) {
213                 if isKind(m[KEY_TYPE], reflect.String) {
214                         if k, ok := m[KEY_TYPE].(string); ok {
215                                 err := currentSchema.types.Add(k)
216                                 if err != nil {
217                                         return err
218                                 }
219                         }
220                 } else {
221                         if isKind(m[KEY_TYPE], reflect.Slice) {
222                                 arrayOfTypes := m[KEY_TYPE].([]interface{})
223                                 for _, typeInArray := range arrayOfTypes {
224                                         if reflect.ValueOf(typeInArray).Kind() != reflect.String {
225                                                 return errors.New(formatErrorDescription(
226                                                         Locale.InvalidType(),
227                                                         ErrorDetails{
228                                                                 "expected": TYPE_STRING + "/" + STRING_ARRAY_OF_STRINGS,
229                                                                 "given":    KEY_TYPE,
230                                                         },
231                                                 ))
232                                         } else {
233                                                 currentSchema.types.Add(typeInArray.(string))
234                                         }
235                                 }
236
237                         } else {
238                                 return errors.New(formatErrorDescription(
239                                         Locale.InvalidType(),
240                                         ErrorDetails{
241                                                 "expected": TYPE_STRING + "/" + STRING_ARRAY_OF_STRINGS,
242                                                 "given":    KEY_TYPE,
243                                         },
244                                 ))
245                         }
246                 }
247         }
248
249         // properties
250         if existsMapKey(m, KEY_PROPERTIES) {
251                 err := d.parseProperties(m[KEY_PROPERTIES], currentSchema)
252                 if err != nil {
253                         return err
254                 }
255         }
256
257         // additionalProperties
258         if existsMapKey(m, KEY_ADDITIONAL_PROPERTIES) {
259                 if isKind(m[KEY_ADDITIONAL_PROPERTIES], reflect.Bool) {
260                         currentSchema.additionalProperties = m[KEY_ADDITIONAL_PROPERTIES].(bool)
261                 } else if isKind(m[KEY_ADDITIONAL_PROPERTIES], reflect.Map) {
262                         newSchema := &subSchema{property: KEY_ADDITIONAL_PROPERTIES, parent: currentSchema, ref: currentSchema.ref}
263                         currentSchema.additionalProperties = newSchema
264                         err := d.parseSchema(m[KEY_ADDITIONAL_PROPERTIES], newSchema)
265                         if err != nil {
266                                 return errors.New(err.Error())
267                         }
268                 } else {
269                         return errors.New(formatErrorDescription(
270                                 Locale.InvalidType(),
271                                 ErrorDetails{
272                                         "expected": TYPE_BOOLEAN + "/" + STRING_SCHEMA,
273                                         "given":    KEY_ADDITIONAL_PROPERTIES,
274                                 },
275                         ))
276                 }
277         }
278
279         // patternProperties
280         if existsMapKey(m, KEY_PATTERN_PROPERTIES) {
281                 if isKind(m[KEY_PATTERN_PROPERTIES], reflect.Map) {
282                         patternPropertiesMap := m[KEY_PATTERN_PROPERTIES].(map[string]interface{})
283                         if len(patternPropertiesMap) > 0 {
284                                 currentSchema.patternProperties = make(map[string]*subSchema)
285                                 for k, v := range patternPropertiesMap {
286                                         _, err := regexp.MatchString(k, "")
287                                         if err != nil {
288                                                 return errors.New(formatErrorDescription(
289                                                         Locale.RegexPattern(),
290                                                         ErrorDetails{"pattern": k},
291                                                 ))
292                                         }
293                                         newSchema := &subSchema{property: k, parent: currentSchema, ref: currentSchema.ref}
294                                         err = d.parseSchema(v, newSchema)
295                                         if err != nil {
296                                                 return errors.New(err.Error())
297                                         }
298                                         currentSchema.patternProperties[k] = newSchema
299                                 }
300                         }
301                 } else {
302                         return errors.New(formatErrorDescription(
303                                 Locale.InvalidType(),
304                                 ErrorDetails{
305                                         "expected": STRING_SCHEMA,
306                                         "given":    KEY_PATTERN_PROPERTIES,
307                                 },
308                         ))
309                 }
310         }
311
312         // dependencies
313         if existsMapKey(m, KEY_DEPENDENCIES) {
314                 err := d.parseDependencies(m[KEY_DEPENDENCIES], currentSchema)
315                 if err != nil {
316                         return err
317                 }
318         }
319
320         // items
321         if existsMapKey(m, KEY_ITEMS) {
322                 if isKind(m[KEY_ITEMS], reflect.Slice) {
323                         for _, itemElement := range m[KEY_ITEMS].([]interface{}) {
324                                 if isKind(itemElement, reflect.Map) {
325                                         newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS}
326                                         newSchema.ref = currentSchema.ref
327                                         currentSchema.AddItemsChild(newSchema)
328                                         err := d.parseSchema(itemElement, newSchema)
329                                         if err != nil {
330                                                 return err
331                                         }
332                                 } else {
333                                         return errors.New(formatErrorDescription(
334                                                 Locale.InvalidType(),
335                                                 ErrorDetails{
336                                                         "expected": STRING_SCHEMA + "/" + STRING_ARRAY_OF_SCHEMAS,
337                                                         "given":    KEY_ITEMS,
338                                                 },
339                                         ))
340                                 }
341                                 currentSchema.itemsChildrenIsSingleSchema = false
342                         }
343                 } else if isKind(m[KEY_ITEMS], reflect.Map) {
344                         newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS}
345                         newSchema.ref = currentSchema.ref
346                         currentSchema.AddItemsChild(newSchema)
347                         err := d.parseSchema(m[KEY_ITEMS], newSchema)
348                         if err != nil {
349                                 return err
350                         }
351                         currentSchema.itemsChildrenIsSingleSchema = true
352                 } else {
353                         return errors.New(formatErrorDescription(
354                                 Locale.InvalidType(),
355                                 ErrorDetails{
356                                         "expected": STRING_SCHEMA + "/" + STRING_ARRAY_OF_SCHEMAS,
357                                         "given":    KEY_ITEMS,
358                                 },
359                         ))
360                 }
361         }
362
363         // additionalItems
364         if existsMapKey(m, KEY_ADDITIONAL_ITEMS) {
365                 if isKind(m[KEY_ADDITIONAL_ITEMS], reflect.Bool) {
366                         currentSchema.additionalItems = m[KEY_ADDITIONAL_ITEMS].(bool)
367                 } else if isKind(m[KEY_ADDITIONAL_ITEMS], reflect.Map) {
368                         newSchema := &subSchema{property: KEY_ADDITIONAL_ITEMS, parent: currentSchema, ref: currentSchema.ref}
369                         currentSchema.additionalItems = newSchema
370                         err := d.parseSchema(m[KEY_ADDITIONAL_ITEMS], newSchema)
371                         if err != nil {
372                                 return errors.New(err.Error())
373                         }
374                 } else {
375                         return errors.New(formatErrorDescription(
376                                 Locale.InvalidType(),
377                                 ErrorDetails{
378                                         "expected": TYPE_BOOLEAN + "/" + STRING_SCHEMA,
379                                         "given":    KEY_ADDITIONAL_ITEMS,
380                                 },
381                         ))
382                 }
383         }
384
385         // validation : number / integer
386
387         if existsMapKey(m, KEY_MULTIPLE_OF) {
388                 multipleOfValue := mustBeNumber(m[KEY_MULTIPLE_OF])
389                 if multipleOfValue == nil {
390                         return errors.New(formatErrorDescription(
391                                 Locale.InvalidType(),
392                                 ErrorDetails{
393                                         "expected": STRING_NUMBER,
394                                         "given":    KEY_MULTIPLE_OF,
395                                 },
396                         ))
397                 }
398                 if *multipleOfValue <= 0 {
399                         return errors.New(formatErrorDescription(
400                                 Locale.GreaterThanZero(),
401                                 ErrorDetails{"number": KEY_MULTIPLE_OF},
402                         ))
403                 }
404                 currentSchema.multipleOf = multipleOfValue
405         }
406
407         if existsMapKey(m, KEY_MINIMUM) {
408                 minimumValue := mustBeNumber(m[KEY_MINIMUM])
409                 if minimumValue == nil {
410                         return errors.New(formatErrorDescription(
411                                 Locale.MustBeOfA(),
412                                 ErrorDetails{"x": KEY_MINIMUM, "y": STRING_NUMBER},
413                         ))
414                 }
415                 currentSchema.minimum = minimumValue
416         }
417
418         if existsMapKey(m, KEY_EXCLUSIVE_MINIMUM) {
419                 if isKind(m[KEY_EXCLUSIVE_MINIMUM], reflect.Bool) {
420                         if currentSchema.minimum == nil {
421                                 return errors.New(formatErrorDescription(
422                                         Locale.CannotBeUsedWithout(),
423                                         ErrorDetails{"x": KEY_EXCLUSIVE_MINIMUM, "y": KEY_MINIMUM},
424                                 ))
425                         }
426                         exclusiveMinimumValue := m[KEY_EXCLUSIVE_MINIMUM].(bool)
427                         currentSchema.exclusiveMinimum = exclusiveMinimumValue
428                 } else {
429                         return errors.New(formatErrorDescription(
430                                 Locale.MustBeOfA(),
431                                 ErrorDetails{"x": KEY_EXCLUSIVE_MINIMUM, "y": TYPE_BOOLEAN},
432                         ))
433                 }
434         }
435
436         if existsMapKey(m, KEY_MAXIMUM) {
437                 maximumValue := mustBeNumber(m[KEY_MAXIMUM])
438                 if maximumValue == nil {
439                         return errors.New(formatErrorDescription(
440                                 Locale.MustBeOfA(),
441                                 ErrorDetails{"x": KEY_MAXIMUM, "y": STRING_NUMBER},
442                         ))
443                 }
444                 currentSchema.maximum = maximumValue
445         }
446
447         if existsMapKey(m, KEY_EXCLUSIVE_MAXIMUM) {
448                 if isKind(m[KEY_EXCLUSIVE_MAXIMUM], reflect.Bool) {
449                         if currentSchema.maximum == nil {
450                                 return errors.New(formatErrorDescription(
451                                         Locale.CannotBeUsedWithout(),
452                                         ErrorDetails{"x": KEY_EXCLUSIVE_MAXIMUM, "y": KEY_MAXIMUM},
453                                 ))
454                         }
455                         exclusiveMaximumValue := m[KEY_EXCLUSIVE_MAXIMUM].(bool)
456                         currentSchema.exclusiveMaximum = exclusiveMaximumValue
457                 } else {
458                         return errors.New(formatErrorDescription(
459                                 Locale.MustBeOfA(),
460                                 ErrorDetails{"x": KEY_EXCLUSIVE_MAXIMUM, "y": STRING_NUMBER},
461                         ))
462                 }
463         }
464
465         if currentSchema.minimum != nil && currentSchema.maximum != nil {
466                 if *currentSchema.minimum > *currentSchema.maximum {
467                         return errors.New(formatErrorDescription(
468                                 Locale.CannotBeGT(),
469                                 ErrorDetails{"x": KEY_MINIMUM, "y": KEY_MAXIMUM},
470                         ))
471                 }
472         }
473
474         // validation : string
475
476         if existsMapKey(m, KEY_MIN_LENGTH) {
477                 minLengthIntegerValue := mustBeInteger(m[KEY_MIN_LENGTH])
478                 if minLengthIntegerValue == nil {
479                         return errors.New(formatErrorDescription(
480                                 Locale.MustBeOfAn(),
481                                 ErrorDetails{"x": KEY_MIN_LENGTH, "y": TYPE_INTEGER},
482                         ))
483                 }
484                 if *minLengthIntegerValue < 0 {
485                         return errors.New(formatErrorDescription(
486                                 Locale.MustBeGTEZero(),
487                                 ErrorDetails{"key": KEY_MIN_LENGTH},
488                         ))
489                 }
490                 currentSchema.minLength = minLengthIntegerValue
491         }
492
493         if existsMapKey(m, KEY_MAX_LENGTH) {
494                 maxLengthIntegerValue := mustBeInteger(m[KEY_MAX_LENGTH])
495                 if maxLengthIntegerValue == nil {
496                         return errors.New(formatErrorDescription(
497                                 Locale.MustBeOfAn(),
498                                 ErrorDetails{"x": KEY_MAX_LENGTH, "y": TYPE_INTEGER},
499                         ))
500                 }
501                 if *maxLengthIntegerValue < 0 {
502                         return errors.New(formatErrorDescription(
503                                 Locale.MustBeGTEZero(),
504                                 ErrorDetails{"key": KEY_MAX_LENGTH},
505                         ))
506                 }
507                 currentSchema.maxLength = maxLengthIntegerValue
508         }
509
510         if currentSchema.minLength != nil && currentSchema.maxLength != nil {
511                 if *currentSchema.minLength > *currentSchema.maxLength {
512                         return errors.New(formatErrorDescription(
513                                 Locale.CannotBeGT(),
514                                 ErrorDetails{"x": KEY_MIN_LENGTH, "y": KEY_MAX_LENGTH},
515                         ))
516                 }
517         }
518
519         if existsMapKey(m, KEY_PATTERN) {
520                 if isKind(m[KEY_PATTERN], reflect.String) {
521                         regexpObject, err := regexp.Compile(m[KEY_PATTERN].(string))
522                         if err != nil {
523                                 return errors.New(formatErrorDescription(
524                                         Locale.MustBeValidRegex(),
525                                         ErrorDetails{"key": KEY_PATTERN},
526                                 ))
527                         }
528                         currentSchema.pattern = regexpObject
529                 } else {
530                         return errors.New(formatErrorDescription(
531                                 Locale.MustBeOfA(),
532                                 ErrorDetails{"x": KEY_PATTERN, "y": TYPE_STRING},
533                         ))
534                 }
535         }
536
537         if existsMapKey(m, KEY_FORMAT) {
538                 formatString, ok := m[KEY_FORMAT].(string)
539                 if ok && FormatCheckers.Has(formatString) {
540                         currentSchema.format = formatString
541                 } else {
542                         return errors.New(formatErrorDescription(
543                                 Locale.MustBeValidFormat(),
544                                 ErrorDetails{"key": KEY_FORMAT, "given": m[KEY_FORMAT]},
545                         ))
546                 }
547         }
548
549         // validation : object
550
551         if existsMapKey(m, KEY_MIN_PROPERTIES) {
552                 minPropertiesIntegerValue := mustBeInteger(m[KEY_MIN_PROPERTIES])
553                 if minPropertiesIntegerValue == nil {
554                         return errors.New(formatErrorDescription(
555                                 Locale.MustBeOfAn(),
556                                 ErrorDetails{"x": KEY_MIN_PROPERTIES, "y": TYPE_INTEGER},
557                         ))
558                 }
559                 if *minPropertiesIntegerValue < 0 {
560                         return errors.New(formatErrorDescription(
561                                 Locale.MustBeGTEZero(),
562                                 ErrorDetails{"key": KEY_MIN_PROPERTIES},
563                         ))
564                 }
565                 currentSchema.minProperties = minPropertiesIntegerValue
566         }
567
568         if existsMapKey(m, KEY_MAX_PROPERTIES) {
569                 maxPropertiesIntegerValue := mustBeInteger(m[KEY_MAX_PROPERTIES])
570                 if maxPropertiesIntegerValue == nil {
571                         return errors.New(formatErrorDescription(
572                                 Locale.MustBeOfAn(),
573                                 ErrorDetails{"x": KEY_MAX_PROPERTIES, "y": TYPE_INTEGER},
574                         ))
575                 }
576                 if *maxPropertiesIntegerValue < 0 {
577                         return errors.New(formatErrorDescription(
578                                 Locale.MustBeGTEZero(),
579                                 ErrorDetails{"key": KEY_MAX_PROPERTIES},
580                         ))
581                 }
582                 currentSchema.maxProperties = maxPropertiesIntegerValue
583         }
584
585         if currentSchema.minProperties != nil && currentSchema.maxProperties != nil {
586                 if *currentSchema.minProperties > *currentSchema.maxProperties {
587                         return errors.New(formatErrorDescription(
588                                 Locale.KeyCannotBeGreaterThan(),
589                                 ErrorDetails{"key": KEY_MIN_PROPERTIES, "y": KEY_MAX_PROPERTIES},
590                         ))
591                 }
592         }
593
594         if existsMapKey(m, KEY_REQUIRED) {
595                 if isKind(m[KEY_REQUIRED], reflect.Slice) {
596                         requiredValues := m[KEY_REQUIRED].([]interface{})
597                         for _, requiredValue := range requiredValues {
598                                 if isKind(requiredValue, reflect.String) {
599                                         err := currentSchema.AddRequired(requiredValue.(string))
600                                         if err != nil {
601                                                 return err
602                                         }
603                                 } else {
604                                         return errors.New(formatErrorDescription(
605                                                 Locale.KeyItemsMustBeOfType(),
606                                                 ErrorDetails{"key": KEY_REQUIRED, "type": TYPE_STRING},
607                                         ))
608                                 }
609                         }
610                 } else {
611                         return errors.New(formatErrorDescription(
612                                 Locale.MustBeOfAn(),
613                                 ErrorDetails{"x": KEY_REQUIRED, "y": TYPE_ARRAY},
614                         ))
615                 }
616         }
617
618         // validation : array
619
620         if existsMapKey(m, KEY_MIN_ITEMS) {
621                 minItemsIntegerValue := mustBeInteger(m[KEY_MIN_ITEMS])
622                 if minItemsIntegerValue == nil {
623                         return errors.New(formatErrorDescription(
624                                 Locale.MustBeOfAn(),
625                                 ErrorDetails{"x": KEY_MIN_ITEMS, "y": TYPE_INTEGER},
626                         ))
627                 }
628                 if *minItemsIntegerValue < 0 {
629                         return errors.New(formatErrorDescription(
630                                 Locale.MustBeGTEZero(),
631                                 ErrorDetails{"key": KEY_MIN_ITEMS},
632                         ))
633                 }
634                 currentSchema.minItems = minItemsIntegerValue
635         }
636
637         if existsMapKey(m, KEY_MAX_ITEMS) {
638                 maxItemsIntegerValue := mustBeInteger(m[KEY_MAX_ITEMS])
639                 if maxItemsIntegerValue == nil {
640                         return errors.New(formatErrorDescription(
641                                 Locale.MustBeOfAn(),
642                                 ErrorDetails{"x": KEY_MAX_ITEMS, "y": TYPE_INTEGER},
643                         ))
644                 }
645                 if *maxItemsIntegerValue < 0 {
646                         return errors.New(formatErrorDescription(
647                                 Locale.MustBeGTEZero(),
648                                 ErrorDetails{"key": KEY_MAX_ITEMS},
649                         ))
650                 }
651                 currentSchema.maxItems = maxItemsIntegerValue
652         }
653
654         if existsMapKey(m, KEY_UNIQUE_ITEMS) {
655                 if isKind(m[KEY_UNIQUE_ITEMS], reflect.Bool) {
656                         currentSchema.uniqueItems = m[KEY_UNIQUE_ITEMS].(bool)
657                 } else {
658                         return errors.New(formatErrorDescription(
659                                 Locale.MustBeOfA(),
660                                 ErrorDetails{"x": KEY_UNIQUE_ITEMS, "y": TYPE_BOOLEAN},
661                         ))
662                 }
663         }
664
665         // validation : all
666
667         if existsMapKey(m, KEY_ENUM) {
668                 if isKind(m[KEY_ENUM], reflect.Slice) {
669                         for _, v := range m[KEY_ENUM].([]interface{}) {
670                                 err := currentSchema.AddEnum(v)
671                                 if err != nil {
672                                         return err
673                                 }
674                         }
675                 } else {
676                         return errors.New(formatErrorDescription(
677                                 Locale.MustBeOfAn(),
678                                 ErrorDetails{"x": KEY_ENUM, "y": TYPE_ARRAY},
679                         ))
680                 }
681         }
682
683         // validation : subSchema
684
685         if existsMapKey(m, KEY_ONE_OF) {
686                 if isKind(m[KEY_ONE_OF], reflect.Slice) {
687                         for _, v := range m[KEY_ONE_OF].([]interface{}) {
688                                 newSchema := &subSchema{property: KEY_ONE_OF, parent: currentSchema, ref: currentSchema.ref}
689                                 currentSchema.AddOneOf(newSchema)
690                                 err := d.parseSchema(v, newSchema)
691                                 if err != nil {
692                                         return err
693                                 }
694                         }
695                 } else {
696                         return errors.New(formatErrorDescription(
697                                 Locale.MustBeOfAn(),
698                                 ErrorDetails{"x": KEY_ONE_OF, "y": TYPE_ARRAY},
699                         ))
700                 }
701         }
702
703         if existsMapKey(m, KEY_ANY_OF) {
704                 if isKind(m[KEY_ANY_OF], reflect.Slice) {
705                         for _, v := range m[KEY_ANY_OF].([]interface{}) {
706                                 newSchema := &subSchema{property: KEY_ANY_OF, parent: currentSchema, ref: currentSchema.ref}
707                                 currentSchema.AddAnyOf(newSchema)
708                                 err := d.parseSchema(v, newSchema)
709                                 if err != nil {
710                                         return err
711                                 }
712                         }
713                 } else {
714                         return errors.New(formatErrorDescription(
715                                 Locale.MustBeOfAn(),
716                                 ErrorDetails{"x": KEY_ANY_OF, "y": TYPE_ARRAY},
717                         ))
718                 }
719         }
720
721         if existsMapKey(m, KEY_ALL_OF) {
722                 if isKind(m[KEY_ALL_OF], reflect.Slice) {
723                         for _, v := range m[KEY_ALL_OF].([]interface{}) {
724                                 newSchema := &subSchema{property: KEY_ALL_OF, parent: currentSchema, ref: currentSchema.ref}
725                                 currentSchema.AddAllOf(newSchema)
726                                 err := d.parseSchema(v, newSchema)
727                                 if err != nil {
728                                         return err
729                                 }
730                         }
731                 } else {
732                         return errors.New(formatErrorDescription(
733                                 Locale.MustBeOfAn(),
734                                 ErrorDetails{"x": KEY_ANY_OF, "y": TYPE_ARRAY},
735                         ))
736                 }
737         }
738
739         if existsMapKey(m, KEY_NOT) {
740                 if isKind(m[KEY_NOT], reflect.Map) {
741                         newSchema := &subSchema{property: KEY_NOT, parent: currentSchema, ref: currentSchema.ref}
742                         currentSchema.SetNot(newSchema)
743                         err := d.parseSchema(m[KEY_NOT], newSchema)
744                         if err != nil {
745                                 return err
746                         }
747                 } else {
748                         return errors.New(formatErrorDescription(
749                                 Locale.MustBeOfAn(),
750                                 ErrorDetails{"x": KEY_NOT, "y": TYPE_OBJECT},
751                         ))
752                 }
753         }
754
755         return nil
756 }
757
758 func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSchema, reference string) (e error) {
759
760         var err error
761
762         jsonReference, err := gojsonreference.NewJsonReference(reference)
763         if err != nil {
764                 return err
765         }
766
767         standaloneDocument := d.pool.GetStandaloneDocument()
768
769         if jsonReference.HasFullUrl {
770                 currentSchema.ref = &jsonReference
771         } else {
772                 inheritedReference, err := currentSchema.ref.Inherits(jsonReference)
773                 if err != nil {
774                         return err
775                 }
776                 currentSchema.ref = inheritedReference
777         }
778
779         jsonPointer := currentSchema.ref.GetPointer()
780
781         var refdDocumentNode interface{}
782
783         if standaloneDocument != nil {
784
785                 var err error
786                 refdDocumentNode, _, err = jsonPointer.Get(standaloneDocument)
787                 if err != nil {
788                         return err
789                 }
790
791         } else {
792
793                 var err error
794                 dsp, err := d.pool.GetDocument(*currentSchema.ref)
795                 if err != nil {
796                         return err
797                 }
798
799                 refdDocumentNode, _, err = jsonPointer.Get(dsp.Document)
800                 if err != nil {
801                         return err
802                 }
803
804         }
805
806         if !isKind(refdDocumentNode, reflect.Map) {
807                 return errors.New(formatErrorDescription(
808                         Locale.MustBeOfType(),
809                         ErrorDetails{"key": STRING_SCHEMA, "type": TYPE_OBJECT},
810                 ))
811         }
812
813         // returns the loaded referenced subSchema for the caller to update its current subSchema
814         newSchemaDocument := refdDocumentNode.(map[string]interface{})
815
816         newSchema := &subSchema{property: KEY_REF, parent: currentSchema, ref: currentSchema.ref}
817         d.referencePool.Add(currentSchema.ref.String()+reference, newSchema)
818
819         err = d.parseSchema(newSchemaDocument, newSchema)
820         if err != nil {
821                 return err
822         }
823
824         currentSchema.refSchema = newSchema
825
826         return nil
827
828 }
829
830 func (d *Schema) parseProperties(documentNode interface{}, currentSchema *subSchema) error {
831
832         if !isKind(documentNode, reflect.Map) {
833                 return errors.New(formatErrorDescription(
834                         Locale.MustBeOfType(),
835                         ErrorDetails{"key": STRING_PROPERTIES, "type": TYPE_OBJECT},
836                 ))
837         }
838
839         m := documentNode.(map[string]interface{})
840         for k := range m {
841                 schemaProperty := k
842                 newSchema := &subSchema{property: schemaProperty, parent: currentSchema, ref: currentSchema.ref}
843                 currentSchema.AddPropertiesChild(newSchema)
844                 err := d.parseSchema(m[k], newSchema)
845                 if err != nil {
846                         return err
847                 }
848         }
849
850         return nil
851 }
852
853 func (d *Schema) parseDependencies(documentNode interface{}, currentSchema *subSchema) error {
854
855         if !isKind(documentNode, reflect.Map) {
856                 return errors.New(formatErrorDescription(
857                         Locale.MustBeOfType(),
858                         ErrorDetails{"key": KEY_DEPENDENCIES, "type": TYPE_OBJECT},
859                 ))
860         }
861
862         m := documentNode.(map[string]interface{})
863         currentSchema.dependencies = make(map[string]interface{})
864
865         for k := range m {
866                 switch reflect.ValueOf(m[k]).Kind() {
867
868                 case reflect.Slice:
869                         values := m[k].([]interface{})
870                         var valuesToRegister []string
871
872                         for _, value := range values {
873                                 if !isKind(value, reflect.String) {
874                                         return errors.New(formatErrorDescription(
875                                                 Locale.MustBeOfType(),
876                                                 ErrorDetails{
877                                                         "key":  STRING_DEPENDENCY,
878                                                         "type": STRING_SCHEMA_OR_ARRAY_OF_STRINGS,
879                                                 },
880                                         ))
881                                 } else {
882                                         valuesToRegister = append(valuesToRegister, value.(string))
883                                 }
884                                 currentSchema.dependencies[k] = valuesToRegister
885                         }
886
887                 case reflect.Map:
888                         depSchema := &subSchema{property: k, parent: currentSchema, ref: currentSchema.ref}
889                         err := d.parseSchema(m[k], depSchema)
890                         if err != nil {
891                                 return err
892                         }
893                         currentSchema.dependencies[k] = depSchema
894
895                 default:
896                         return errors.New(formatErrorDescription(
897                                 Locale.MustBeOfType(),
898                                 ErrorDetails{
899                                         "key":  STRING_DEPENDENCY,
900                                         "type": STRING_SCHEMA_OR_ARRAY_OF_STRINGS,
901                                 },
902                         ))
903                 }
904
905         }
906
907         return nil
908 }