1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gojsonschema
28
29 import (
30 "errors"
31 "math/big"
32 "reflect"
33 "regexp"
34 "text/template"
35
36 "github.com/xeipuuv/gojsonreference"
37 )
38
39 var (
40
41
42 Locale locale = DefaultLocale{}
43
44
45 ErrorTemplateFuncs template.FuncMap
46 )
47
48
49 func NewSchema(l JSONLoader) (*Schema, error) {
50 return NewSchemaLoader().Compile(l)
51 }
52
53
54 type Schema struct {
55 documentReference gojsonreference.JsonReference
56 rootSchema *subSchema
57 pool *schemaPool
58 referencePool *schemaReferencePool
59 }
60
61 func (d *Schema) parse(document interface{}, draft Draft) error {
62 d.rootSchema = &subSchema{property: STRING_ROOT_SCHEMA_PROPERTY, draft: &draft}
63 return d.parseSchema(document, d.rootSchema)
64 }
65
66
67 func (d *Schema) SetRootSchemaName(name string) {
68 d.rootSchema.property = name
69 }
70
71
72
73
74
75
76
77 func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema) error {
78
79 if currentSchema.draft == nil {
80 if currentSchema.parent == nil {
81 return errors.New("Draft not set")
82 }
83 currentSchema.draft = currentSchema.parent.draft
84 }
85
86
87 if *currentSchema.draft >= Draft6 && isKind(documentNode, reflect.Bool) {
88 b := documentNode.(bool)
89 currentSchema.pass = &b
90 return nil
91 }
92
93 if !isKind(documentNode, reflect.Map) {
94 return errors.New(formatErrorDescription(
95 Locale.ParseError(),
96 ErrorDetails{
97 "expected": STRING_SCHEMA,
98 },
99 ))
100 }
101
102 m := documentNode.(map[string]interface{})
103
104 if currentSchema.parent == nil {
105 currentSchema.ref = &d.documentReference
106 currentSchema.id = &d.documentReference
107 }
108
109 if currentSchema.id == nil && currentSchema.parent != nil {
110 currentSchema.id = currentSchema.parent.id
111 }
112
113
114
115 var keyID string
116
117 switch *currentSchema.draft {
118 case Draft4:
119 keyID = KEY_ID
120 case Hybrid:
121 keyID = KEY_ID_NEW
122 if existsMapKey(m, KEY_ID) {
123 keyID = KEY_ID
124 }
125 default:
126 keyID = KEY_ID_NEW
127 }
128 if existsMapKey(m, keyID) && !isKind(m[keyID], reflect.String) {
129 return errors.New(formatErrorDescription(
130 Locale.InvalidType(),
131 ErrorDetails{
132 "expected": TYPE_STRING,
133 "given": keyID,
134 },
135 ))
136 }
137 if k, ok := m[keyID].(string); ok {
138 jsonReference, err := gojsonreference.NewJsonReference(k)
139 if err != nil {
140 return err
141 }
142 if currentSchema == d.rootSchema {
143 currentSchema.id = &jsonReference
144 } else {
145 ref, err := currentSchema.parent.id.Inherits(jsonReference)
146 if err != nil {
147 return err
148 }
149 currentSchema.id = ref
150 }
151 }
152
153
154 if existsMapKey(m, KEY_DEFINITIONS) {
155 if isKind(m[KEY_DEFINITIONS], reflect.Map, reflect.Bool) {
156 for _, dv := range m[KEY_DEFINITIONS].(map[string]interface{}) {
157 if isKind(dv, reflect.Map, reflect.Bool) {
158
159 newSchema := &subSchema{property: KEY_DEFINITIONS, parent: currentSchema}
160
161 err := d.parseSchema(dv, newSchema)
162
163 if err != nil {
164 return err
165 }
166 } else {
167 return errors.New(formatErrorDescription(
168 Locale.InvalidType(),
169 ErrorDetails{
170 "expected": STRING_ARRAY_OF_SCHEMAS,
171 "given": KEY_DEFINITIONS,
172 },
173 ))
174 }
175 }
176 } else {
177 return errors.New(formatErrorDescription(
178 Locale.InvalidType(),
179 ErrorDetails{
180 "expected": STRING_ARRAY_OF_SCHEMAS,
181 "given": KEY_DEFINITIONS,
182 },
183 ))
184 }
185
186 }
187
188
189 if existsMapKey(m, KEY_TITLE) && !isKind(m[KEY_TITLE], reflect.String) {
190 return errors.New(formatErrorDescription(
191 Locale.InvalidType(),
192 ErrorDetails{
193 "expected": TYPE_STRING,
194 "given": KEY_TITLE,
195 },
196 ))
197 }
198 if k, ok := m[KEY_TITLE].(string); ok {
199 currentSchema.title = &k
200 }
201
202
203 if existsMapKey(m, KEY_DESCRIPTION) && !isKind(m[KEY_DESCRIPTION], reflect.String) {
204 return errors.New(formatErrorDescription(
205 Locale.InvalidType(),
206 ErrorDetails{
207 "expected": TYPE_STRING,
208 "given": KEY_DESCRIPTION,
209 },
210 ))
211 }
212 if k, ok := m[KEY_DESCRIPTION].(string); ok {
213 currentSchema.description = &k
214 }
215
216
217 if existsMapKey(m, KEY_REF) && !isKind(m[KEY_REF], reflect.String) {
218 return errors.New(formatErrorDescription(
219 Locale.InvalidType(),
220 ErrorDetails{
221 "expected": TYPE_STRING,
222 "given": KEY_REF,
223 },
224 ))
225 }
226
227 if k, ok := m[KEY_REF].(string); ok {
228
229 jsonReference, err := gojsonreference.NewJsonReference(k)
230 if err != nil {
231 return err
232 }
233
234 currentSchema.ref = &jsonReference
235
236 if sch, ok := d.referencePool.Get(currentSchema.ref.String()); ok {
237 currentSchema.refSchema = sch
238 } else {
239 err := d.parseReference(documentNode, currentSchema)
240
241 if err != nil {
242 return err
243 }
244
245 return nil
246 }
247 }
248
249
250 if existsMapKey(m, KEY_TYPE) {
251 if isKind(m[KEY_TYPE], reflect.String) {
252 if k, ok := m[KEY_TYPE].(string); ok {
253 err := currentSchema.types.Add(k)
254 if err != nil {
255 return err
256 }
257 }
258 } else {
259 if isKind(m[KEY_TYPE], reflect.Slice) {
260 arrayOfTypes := m[KEY_TYPE].([]interface{})
261 for _, typeInArray := range arrayOfTypes {
262 if reflect.ValueOf(typeInArray).Kind() != reflect.String {
263 return errors.New(formatErrorDescription(
264 Locale.InvalidType(),
265 ErrorDetails{
266 "expected": TYPE_STRING + "/" + STRING_ARRAY_OF_STRINGS,
267 "given": KEY_TYPE,
268 },
269 ))
270 }
271 if err := currentSchema.types.Add(typeInArray.(string)); err != nil {
272 return err
273 }
274 }
275
276 } else {
277 return errors.New(formatErrorDescription(
278 Locale.InvalidType(),
279 ErrorDetails{
280 "expected": TYPE_STRING + "/" + STRING_ARRAY_OF_STRINGS,
281 "given": KEY_TYPE,
282 },
283 ))
284 }
285 }
286 }
287
288
289 if existsMapKey(m, KEY_PROPERTIES) {
290 err := d.parseProperties(m[KEY_PROPERTIES], currentSchema)
291 if err != nil {
292 return err
293 }
294 }
295
296
297 if existsMapKey(m, KEY_ADDITIONAL_PROPERTIES) {
298 if isKind(m[KEY_ADDITIONAL_PROPERTIES], reflect.Bool) {
299 currentSchema.additionalProperties = m[KEY_ADDITIONAL_PROPERTIES].(bool)
300 } else if isKind(m[KEY_ADDITIONAL_PROPERTIES], reflect.Map) {
301 newSchema := &subSchema{property: KEY_ADDITIONAL_PROPERTIES, parent: currentSchema, ref: currentSchema.ref}
302 currentSchema.additionalProperties = newSchema
303 err := d.parseSchema(m[KEY_ADDITIONAL_PROPERTIES], newSchema)
304 if err != nil {
305 return errors.New(err.Error())
306 }
307 } else {
308 return errors.New(formatErrorDescription(
309 Locale.InvalidType(),
310 ErrorDetails{
311 "expected": TYPE_BOOLEAN + "/" + STRING_SCHEMA,
312 "given": KEY_ADDITIONAL_PROPERTIES,
313 },
314 ))
315 }
316 }
317
318
319 if existsMapKey(m, KEY_PATTERN_PROPERTIES) {
320 if isKind(m[KEY_PATTERN_PROPERTIES], reflect.Map) {
321 patternPropertiesMap := m[KEY_PATTERN_PROPERTIES].(map[string]interface{})
322 if len(patternPropertiesMap) > 0 {
323 currentSchema.patternProperties = make(map[string]*subSchema)
324 for k, v := range patternPropertiesMap {
325 _, err := regexp.MatchString(k, "")
326 if err != nil {
327 return errors.New(formatErrorDescription(
328 Locale.RegexPattern(),
329 ErrorDetails{"pattern": k},
330 ))
331 }
332 newSchema := &subSchema{property: k, parent: currentSchema, ref: currentSchema.ref}
333 err = d.parseSchema(v, newSchema)
334 if err != nil {
335 return errors.New(err.Error())
336 }
337 currentSchema.patternProperties[k] = newSchema
338 }
339 }
340 } else {
341 return errors.New(formatErrorDescription(
342 Locale.InvalidType(),
343 ErrorDetails{
344 "expected": STRING_SCHEMA,
345 "given": KEY_PATTERN_PROPERTIES,
346 },
347 ))
348 }
349 }
350
351
352 if existsMapKey(m, KEY_PROPERTY_NAMES) && *currentSchema.draft >= Draft6 {
353 if isKind(m[KEY_PROPERTY_NAMES], reflect.Map, reflect.Bool) {
354 newSchema := &subSchema{property: KEY_PROPERTY_NAMES, parent: currentSchema, ref: currentSchema.ref}
355 currentSchema.propertyNames = newSchema
356 err := d.parseSchema(m[KEY_PROPERTY_NAMES], newSchema)
357 if err != nil {
358 return err
359 }
360 } else {
361 return errors.New(formatErrorDescription(
362 Locale.InvalidType(),
363 ErrorDetails{
364 "expected": STRING_SCHEMA,
365 "given": KEY_PATTERN_PROPERTIES,
366 },
367 ))
368 }
369 }
370
371
372 if existsMapKey(m, KEY_DEPENDENCIES) {
373 err := d.parseDependencies(m[KEY_DEPENDENCIES], currentSchema)
374 if err != nil {
375 return err
376 }
377 }
378
379
380 if existsMapKey(m, KEY_ITEMS) {
381 if isKind(m[KEY_ITEMS], reflect.Slice) {
382 for _, itemElement := range m[KEY_ITEMS].([]interface{}) {
383 if isKind(itemElement, reflect.Map, reflect.Bool) {
384 newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS}
385 newSchema.ref = currentSchema.ref
386 currentSchema.itemsChildren = append(currentSchema.itemsChildren, newSchema)
387 err := d.parseSchema(itemElement, newSchema)
388 if err != nil {
389 return err
390 }
391 } else {
392 return errors.New(formatErrorDescription(
393 Locale.InvalidType(),
394 ErrorDetails{
395 "expected": STRING_SCHEMA + "/" + STRING_ARRAY_OF_SCHEMAS,
396 "given": KEY_ITEMS,
397 },
398 ))
399 }
400 currentSchema.itemsChildrenIsSingleSchema = false
401 }
402 } else if isKind(m[KEY_ITEMS], reflect.Map, reflect.Bool) {
403 newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS}
404 newSchema.ref = currentSchema.ref
405 currentSchema.itemsChildren = append(currentSchema.itemsChildren, newSchema)
406 err := d.parseSchema(m[KEY_ITEMS], newSchema)
407 if err != nil {
408 return err
409 }
410 currentSchema.itemsChildrenIsSingleSchema = true
411 } else {
412 return errors.New(formatErrorDescription(
413 Locale.InvalidType(),
414 ErrorDetails{
415 "expected": STRING_SCHEMA + "/" + STRING_ARRAY_OF_SCHEMAS,
416 "given": KEY_ITEMS,
417 },
418 ))
419 }
420 }
421
422
423 if existsMapKey(m, KEY_ADDITIONAL_ITEMS) {
424 if isKind(m[KEY_ADDITIONAL_ITEMS], reflect.Bool) {
425 currentSchema.additionalItems = m[KEY_ADDITIONAL_ITEMS].(bool)
426 } else if isKind(m[KEY_ADDITIONAL_ITEMS], reflect.Map) {
427 newSchema := &subSchema{property: KEY_ADDITIONAL_ITEMS, parent: currentSchema, ref: currentSchema.ref}
428 currentSchema.additionalItems = newSchema
429 err := d.parseSchema(m[KEY_ADDITIONAL_ITEMS], newSchema)
430 if err != nil {
431 return errors.New(err.Error())
432 }
433 } else {
434 return errors.New(formatErrorDescription(
435 Locale.InvalidType(),
436 ErrorDetails{
437 "expected": TYPE_BOOLEAN + "/" + STRING_SCHEMA,
438 "given": KEY_ADDITIONAL_ITEMS,
439 },
440 ))
441 }
442 }
443
444
445
446 if existsMapKey(m, KEY_MULTIPLE_OF) {
447 multipleOfValue := mustBeNumber(m[KEY_MULTIPLE_OF])
448 if multipleOfValue == nil {
449 return errors.New(formatErrorDescription(
450 Locale.InvalidType(),
451 ErrorDetails{
452 "expected": STRING_NUMBER,
453 "given": KEY_MULTIPLE_OF,
454 },
455 ))
456 }
457 if multipleOfValue.Cmp(big.NewRat(0, 1)) <= 0 {
458 return errors.New(formatErrorDescription(
459 Locale.GreaterThanZero(),
460 ErrorDetails{"number": KEY_MULTIPLE_OF},
461 ))
462 }
463 currentSchema.multipleOf = multipleOfValue
464 }
465
466 if existsMapKey(m, KEY_MINIMUM) {
467 minimumValue := mustBeNumber(m[KEY_MINIMUM])
468 if minimumValue == nil {
469 return errors.New(formatErrorDescription(
470 Locale.MustBeOfA(),
471 ErrorDetails{"x": KEY_MINIMUM, "y": STRING_NUMBER},
472 ))
473 }
474 currentSchema.minimum = minimumValue
475 }
476
477 if existsMapKey(m, KEY_EXCLUSIVE_MINIMUM) {
478 switch *currentSchema.draft {
479 case Draft4:
480 if !isKind(m[KEY_EXCLUSIVE_MINIMUM], reflect.Bool) {
481 return errors.New(formatErrorDescription(
482 Locale.InvalidType(),
483 ErrorDetails{
484 "expected": TYPE_BOOLEAN,
485 "given": KEY_EXCLUSIVE_MINIMUM,
486 },
487 ))
488 }
489 if currentSchema.minimum == nil {
490 return errors.New(formatErrorDescription(
491 Locale.CannotBeUsedWithout(),
492 ErrorDetails{"x": KEY_EXCLUSIVE_MINIMUM, "y": KEY_MINIMUM},
493 ))
494 }
495 if m[KEY_EXCLUSIVE_MINIMUM].(bool) {
496 currentSchema.exclusiveMinimum = currentSchema.minimum
497 currentSchema.minimum = nil
498 }
499 case Hybrid:
500 if isKind(m[KEY_EXCLUSIVE_MINIMUM], reflect.Bool) {
501 if currentSchema.minimum == nil {
502 return errors.New(formatErrorDescription(
503 Locale.CannotBeUsedWithout(),
504 ErrorDetails{"x": KEY_EXCLUSIVE_MINIMUM, "y": KEY_MINIMUM},
505 ))
506 }
507 if m[KEY_EXCLUSIVE_MINIMUM].(bool) {
508 currentSchema.exclusiveMinimum = currentSchema.minimum
509 currentSchema.minimum = nil
510 }
511 } else if isJSONNumber(m[KEY_EXCLUSIVE_MINIMUM]) {
512 currentSchema.exclusiveMinimum = mustBeNumber(m[KEY_EXCLUSIVE_MINIMUM])
513 } else {
514 return errors.New(formatErrorDescription(
515 Locale.InvalidType(),
516 ErrorDetails{
517 "expected": TYPE_BOOLEAN + "/" + TYPE_NUMBER,
518 "given": KEY_EXCLUSIVE_MINIMUM,
519 },
520 ))
521 }
522 default:
523 if isJSONNumber(m[KEY_EXCLUSIVE_MINIMUM]) {
524 currentSchema.exclusiveMinimum = mustBeNumber(m[KEY_EXCLUSIVE_MINIMUM])
525 } else {
526 return errors.New(formatErrorDescription(
527 Locale.InvalidType(),
528 ErrorDetails{
529 "expected": TYPE_NUMBER,
530 "given": KEY_EXCLUSIVE_MINIMUM,
531 },
532 ))
533 }
534 }
535 }
536
537 if existsMapKey(m, KEY_MAXIMUM) {
538 maximumValue := mustBeNumber(m[KEY_MAXIMUM])
539 if maximumValue == nil {
540 return errors.New(formatErrorDescription(
541 Locale.MustBeOfA(),
542 ErrorDetails{"x": KEY_MAXIMUM, "y": STRING_NUMBER},
543 ))
544 }
545 currentSchema.maximum = maximumValue
546 }
547
548 if existsMapKey(m, KEY_EXCLUSIVE_MAXIMUM) {
549 switch *currentSchema.draft {
550 case Draft4:
551 if !isKind(m[KEY_EXCLUSIVE_MAXIMUM], reflect.Bool) {
552 return errors.New(formatErrorDescription(
553 Locale.InvalidType(),
554 ErrorDetails{
555 "expected": TYPE_BOOLEAN,
556 "given": KEY_EXCLUSIVE_MAXIMUM,
557 },
558 ))
559 }
560 if currentSchema.maximum == nil {
561 return errors.New(formatErrorDescription(
562 Locale.CannotBeUsedWithout(),
563 ErrorDetails{"x": KEY_EXCLUSIVE_MAXIMUM, "y": KEY_MAXIMUM},
564 ))
565 }
566 if m[KEY_EXCLUSIVE_MAXIMUM].(bool) {
567 currentSchema.exclusiveMaximum = currentSchema.maximum
568 currentSchema.maximum = nil
569 }
570 case Hybrid:
571 if isKind(m[KEY_EXCLUSIVE_MAXIMUM], reflect.Bool) {
572 if currentSchema.maximum == nil {
573 return errors.New(formatErrorDescription(
574 Locale.CannotBeUsedWithout(),
575 ErrorDetails{"x": KEY_EXCLUSIVE_MAXIMUM, "y": KEY_MAXIMUM},
576 ))
577 }
578 if m[KEY_EXCLUSIVE_MAXIMUM].(bool) {
579 currentSchema.exclusiveMaximum = currentSchema.maximum
580 currentSchema.maximum = nil
581 }
582 } else if isJSONNumber(m[KEY_EXCLUSIVE_MAXIMUM]) {
583 currentSchema.exclusiveMaximum = mustBeNumber(m[KEY_EXCLUSIVE_MAXIMUM])
584 } else {
585 return errors.New(formatErrorDescription(
586 Locale.InvalidType(),
587 ErrorDetails{
588 "expected": TYPE_BOOLEAN + "/" + TYPE_NUMBER,
589 "given": KEY_EXCLUSIVE_MAXIMUM,
590 },
591 ))
592 }
593 default:
594 if isJSONNumber(m[KEY_EXCLUSIVE_MAXIMUM]) {
595 currentSchema.exclusiveMaximum = mustBeNumber(m[KEY_EXCLUSIVE_MAXIMUM])
596 } else {
597 return errors.New(formatErrorDescription(
598 Locale.InvalidType(),
599 ErrorDetails{
600 "expected": TYPE_NUMBER,
601 "given": KEY_EXCLUSIVE_MAXIMUM,
602 },
603 ))
604 }
605 }
606 }
607
608
609
610 if existsMapKey(m, KEY_MIN_LENGTH) {
611 minLengthIntegerValue := mustBeInteger(m[KEY_MIN_LENGTH])
612 if minLengthIntegerValue == nil {
613 return errors.New(formatErrorDescription(
614 Locale.MustBeOfAn(),
615 ErrorDetails{"x": KEY_MIN_LENGTH, "y": TYPE_INTEGER},
616 ))
617 }
618 if *minLengthIntegerValue < 0 {
619 return errors.New(formatErrorDescription(
620 Locale.MustBeGTEZero(),
621 ErrorDetails{"key": KEY_MIN_LENGTH},
622 ))
623 }
624 currentSchema.minLength = minLengthIntegerValue
625 }
626
627 if existsMapKey(m, KEY_MAX_LENGTH) {
628 maxLengthIntegerValue := mustBeInteger(m[KEY_MAX_LENGTH])
629 if maxLengthIntegerValue == nil {
630 return errors.New(formatErrorDescription(
631 Locale.MustBeOfAn(),
632 ErrorDetails{"x": KEY_MAX_LENGTH, "y": TYPE_INTEGER},
633 ))
634 }
635 if *maxLengthIntegerValue < 0 {
636 return errors.New(formatErrorDescription(
637 Locale.MustBeGTEZero(),
638 ErrorDetails{"key": KEY_MAX_LENGTH},
639 ))
640 }
641 currentSchema.maxLength = maxLengthIntegerValue
642 }
643
644 if currentSchema.minLength != nil && currentSchema.maxLength != nil {
645 if *currentSchema.minLength > *currentSchema.maxLength {
646 return errors.New(formatErrorDescription(
647 Locale.CannotBeGT(),
648 ErrorDetails{"x": KEY_MIN_LENGTH, "y": KEY_MAX_LENGTH},
649 ))
650 }
651 }
652
653 if existsMapKey(m, KEY_PATTERN) {
654 if isKind(m[KEY_PATTERN], reflect.String) {
655 regexpObject, err := regexp.Compile(m[KEY_PATTERN].(string))
656 if err != nil {
657 return errors.New(formatErrorDescription(
658 Locale.MustBeValidRegex(),
659 ErrorDetails{"key": KEY_PATTERN},
660 ))
661 }
662 currentSchema.pattern = regexpObject
663 } else {
664 return errors.New(formatErrorDescription(
665 Locale.MustBeOfA(),
666 ErrorDetails{"x": KEY_PATTERN, "y": TYPE_STRING},
667 ))
668 }
669 }
670
671 if existsMapKey(m, KEY_FORMAT) {
672 formatString, ok := m[KEY_FORMAT].(string)
673 if !ok {
674 return errors.New(formatErrorDescription(
675 Locale.MustBeOfType(),
676 ErrorDetails{"key": KEY_FORMAT, "type": TYPE_STRING},
677 ))
678 }
679 currentSchema.format = formatString
680 }
681
682
683
684 if existsMapKey(m, KEY_MIN_PROPERTIES) {
685 minPropertiesIntegerValue := mustBeInteger(m[KEY_MIN_PROPERTIES])
686 if minPropertiesIntegerValue == nil {
687 return errors.New(formatErrorDescription(
688 Locale.MustBeOfAn(),
689 ErrorDetails{"x": KEY_MIN_PROPERTIES, "y": TYPE_INTEGER},
690 ))
691 }
692 if *minPropertiesIntegerValue < 0 {
693 return errors.New(formatErrorDescription(
694 Locale.MustBeGTEZero(),
695 ErrorDetails{"key": KEY_MIN_PROPERTIES},
696 ))
697 }
698 currentSchema.minProperties = minPropertiesIntegerValue
699 }
700
701 if existsMapKey(m, KEY_MAX_PROPERTIES) {
702 maxPropertiesIntegerValue := mustBeInteger(m[KEY_MAX_PROPERTIES])
703 if maxPropertiesIntegerValue == nil {
704 return errors.New(formatErrorDescription(
705 Locale.MustBeOfAn(),
706 ErrorDetails{"x": KEY_MAX_PROPERTIES, "y": TYPE_INTEGER},
707 ))
708 }
709 if *maxPropertiesIntegerValue < 0 {
710 return errors.New(formatErrorDescription(
711 Locale.MustBeGTEZero(),
712 ErrorDetails{"key": KEY_MAX_PROPERTIES},
713 ))
714 }
715 currentSchema.maxProperties = maxPropertiesIntegerValue
716 }
717
718 if currentSchema.minProperties != nil && currentSchema.maxProperties != nil {
719 if *currentSchema.minProperties > *currentSchema.maxProperties {
720 return errors.New(formatErrorDescription(
721 Locale.KeyCannotBeGreaterThan(),
722 ErrorDetails{"key": KEY_MIN_PROPERTIES, "y": KEY_MAX_PROPERTIES},
723 ))
724 }
725 }
726
727 if existsMapKey(m, KEY_REQUIRED) {
728 if isKind(m[KEY_REQUIRED], reflect.Slice) {
729 requiredValues := m[KEY_REQUIRED].([]interface{})
730 for _, requiredValue := range requiredValues {
731 if isKind(requiredValue, reflect.String) {
732 if isStringInSlice(currentSchema.required, requiredValue.(string)) {
733 return errors.New(formatErrorDescription(
734 Locale.KeyItemsMustBeUnique(),
735 ErrorDetails{"key": KEY_REQUIRED},
736 ))
737 }
738 currentSchema.required = append(currentSchema.required, requiredValue.(string))
739 } else {
740 return errors.New(formatErrorDescription(
741 Locale.KeyItemsMustBeOfType(),
742 ErrorDetails{"key": KEY_REQUIRED, "type": TYPE_STRING},
743 ))
744 }
745 }
746 } else {
747 return errors.New(formatErrorDescription(
748 Locale.MustBeOfAn(),
749 ErrorDetails{"x": KEY_REQUIRED, "y": TYPE_ARRAY},
750 ))
751 }
752 }
753
754
755
756 if existsMapKey(m, KEY_MIN_ITEMS) {
757 minItemsIntegerValue := mustBeInteger(m[KEY_MIN_ITEMS])
758 if minItemsIntegerValue == nil {
759 return errors.New(formatErrorDescription(
760 Locale.MustBeOfAn(),
761 ErrorDetails{"x": KEY_MIN_ITEMS, "y": TYPE_INTEGER},
762 ))
763 }
764 if *minItemsIntegerValue < 0 {
765 return errors.New(formatErrorDescription(
766 Locale.MustBeGTEZero(),
767 ErrorDetails{"key": KEY_MIN_ITEMS},
768 ))
769 }
770 currentSchema.minItems = minItemsIntegerValue
771 }
772
773 if existsMapKey(m, KEY_MAX_ITEMS) {
774 maxItemsIntegerValue := mustBeInteger(m[KEY_MAX_ITEMS])
775 if maxItemsIntegerValue == nil {
776 return errors.New(formatErrorDescription(
777 Locale.MustBeOfAn(),
778 ErrorDetails{"x": KEY_MAX_ITEMS, "y": TYPE_INTEGER},
779 ))
780 }
781 if *maxItemsIntegerValue < 0 {
782 return errors.New(formatErrorDescription(
783 Locale.MustBeGTEZero(),
784 ErrorDetails{"key": KEY_MAX_ITEMS},
785 ))
786 }
787 currentSchema.maxItems = maxItemsIntegerValue
788 }
789
790 if existsMapKey(m, KEY_UNIQUE_ITEMS) {
791 if isKind(m[KEY_UNIQUE_ITEMS], reflect.Bool) {
792 currentSchema.uniqueItems = m[KEY_UNIQUE_ITEMS].(bool)
793 } else {
794 return errors.New(formatErrorDescription(
795 Locale.MustBeOfA(),
796 ErrorDetails{"x": KEY_UNIQUE_ITEMS, "y": TYPE_BOOLEAN},
797 ))
798 }
799 }
800
801 if existsMapKey(m, KEY_CONTAINS) && *currentSchema.draft >= Draft6 {
802 newSchema := &subSchema{property: KEY_CONTAINS, parent: currentSchema, ref: currentSchema.ref}
803 currentSchema.contains = newSchema
804 err := d.parseSchema(m[KEY_CONTAINS], newSchema)
805 if err != nil {
806 return err
807 }
808 }
809
810
811
812 if existsMapKey(m, KEY_CONST) && *currentSchema.draft >= Draft6 {
813 is, err := marshalWithoutNumber(m[KEY_CONST])
814 if err != nil {
815 return err
816 }
817 currentSchema._const = is
818 }
819
820 if existsMapKey(m, KEY_ENUM) {
821 if isKind(m[KEY_ENUM], reflect.Slice) {
822 for _, v := range m[KEY_ENUM].([]interface{}) {
823 is, err := marshalWithoutNumber(v)
824 if err != nil {
825 return err
826 }
827 if isStringInSlice(currentSchema.enum, *is) {
828 return errors.New(formatErrorDescription(
829 Locale.KeyItemsMustBeUnique(),
830 ErrorDetails{"key": KEY_ENUM},
831 ))
832 }
833 currentSchema.enum = append(currentSchema.enum, *is)
834 }
835 } else {
836 return errors.New(formatErrorDescription(
837 Locale.MustBeOfAn(),
838 ErrorDetails{"x": KEY_ENUM, "y": TYPE_ARRAY},
839 ))
840 }
841 }
842
843
844
845 if existsMapKey(m, KEY_ONE_OF) {
846 if isKind(m[KEY_ONE_OF], reflect.Slice) {
847 for _, v := range m[KEY_ONE_OF].([]interface{}) {
848 newSchema := &subSchema{property: KEY_ONE_OF, parent: currentSchema, ref: currentSchema.ref}
849 currentSchema.oneOf = append(currentSchema.oneOf, newSchema)
850 err := d.parseSchema(v, newSchema)
851 if err != nil {
852 return err
853 }
854 }
855 } else {
856 return errors.New(formatErrorDescription(
857 Locale.MustBeOfAn(),
858 ErrorDetails{"x": KEY_ONE_OF, "y": TYPE_ARRAY},
859 ))
860 }
861 }
862
863 if existsMapKey(m, KEY_ANY_OF) {
864 if isKind(m[KEY_ANY_OF], reflect.Slice) {
865 for _, v := range m[KEY_ANY_OF].([]interface{}) {
866 newSchema := &subSchema{property: KEY_ANY_OF, parent: currentSchema, ref: currentSchema.ref}
867 currentSchema.anyOf = append(currentSchema.anyOf, newSchema)
868 err := d.parseSchema(v, newSchema)
869 if err != nil {
870 return err
871 }
872 }
873 } else {
874 return errors.New(formatErrorDescription(
875 Locale.MustBeOfAn(),
876 ErrorDetails{"x": KEY_ANY_OF, "y": TYPE_ARRAY},
877 ))
878 }
879 }
880
881 if existsMapKey(m, KEY_ALL_OF) {
882 if isKind(m[KEY_ALL_OF], reflect.Slice) {
883 for _, v := range m[KEY_ALL_OF].([]interface{}) {
884 newSchema := &subSchema{property: KEY_ALL_OF, parent: currentSchema, ref: currentSchema.ref}
885 currentSchema.allOf = append(currentSchema.allOf, newSchema)
886 err := d.parseSchema(v, newSchema)
887 if err != nil {
888 return err
889 }
890 }
891 } else {
892 return errors.New(formatErrorDescription(
893 Locale.MustBeOfAn(),
894 ErrorDetails{"x": KEY_ANY_OF, "y": TYPE_ARRAY},
895 ))
896 }
897 }
898
899 if existsMapKey(m, KEY_NOT) {
900 if isKind(m[KEY_NOT], reflect.Map, reflect.Bool) {
901 newSchema := &subSchema{property: KEY_NOT, parent: currentSchema, ref: currentSchema.ref}
902 currentSchema.not = newSchema
903 err := d.parseSchema(m[KEY_NOT], newSchema)
904 if err != nil {
905 return err
906 }
907 } else {
908 return errors.New(formatErrorDescription(
909 Locale.MustBeOfAn(),
910 ErrorDetails{"x": KEY_NOT, "y": TYPE_OBJECT},
911 ))
912 }
913 }
914
915 if *currentSchema.draft >= Draft7 {
916 if existsMapKey(m, KEY_IF) {
917 if isKind(m[KEY_IF], reflect.Map, reflect.Bool) {
918 newSchema := &subSchema{property: KEY_IF, parent: currentSchema, ref: currentSchema.ref}
919 currentSchema._if = newSchema
920 err := d.parseSchema(m[KEY_IF], newSchema)
921 if err != nil {
922 return err
923 }
924 } else {
925 return errors.New(formatErrorDescription(
926 Locale.MustBeOfAn(),
927 ErrorDetails{"x": KEY_IF, "y": TYPE_OBJECT},
928 ))
929 }
930 }
931
932 if existsMapKey(m, KEY_THEN) {
933 if isKind(m[KEY_THEN], reflect.Map, reflect.Bool) {
934 newSchema := &subSchema{property: KEY_THEN, parent: currentSchema, ref: currentSchema.ref}
935 currentSchema._then = newSchema
936 err := d.parseSchema(m[KEY_THEN], newSchema)
937 if err != nil {
938 return err
939 }
940 } else {
941 return errors.New(formatErrorDescription(
942 Locale.MustBeOfAn(),
943 ErrorDetails{"x": KEY_THEN, "y": TYPE_OBJECT},
944 ))
945 }
946 }
947
948 if existsMapKey(m, KEY_ELSE) {
949 if isKind(m[KEY_ELSE], reflect.Map, reflect.Bool) {
950 newSchema := &subSchema{property: KEY_ELSE, parent: currentSchema, ref: currentSchema.ref}
951 currentSchema._else = newSchema
952 err := d.parseSchema(m[KEY_ELSE], newSchema)
953 if err != nil {
954 return err
955 }
956 } else {
957 return errors.New(formatErrorDescription(
958 Locale.MustBeOfAn(),
959 ErrorDetails{"x": KEY_ELSE, "y": TYPE_OBJECT},
960 ))
961 }
962 }
963 }
964
965 return nil
966 }
967
968 func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSchema) error {
969 var (
970 refdDocumentNode interface{}
971 dsp *schemaPoolDocument
972 err error
973 )
974
975 newSchema := &subSchema{property: KEY_REF, parent: currentSchema, ref: currentSchema.ref}
976
977 d.referencePool.Add(currentSchema.ref.String(), newSchema)
978
979 dsp, err = d.pool.GetDocument(*currentSchema.ref)
980 if err != nil {
981 return err
982 }
983 newSchema.id = currentSchema.ref
984
985 refdDocumentNode = dsp.Document
986 newSchema.draft = dsp.Draft
987
988 if err != nil {
989 return err
990 }
991
992 if !isKind(refdDocumentNode, reflect.Map, reflect.Bool) {
993 return errors.New(formatErrorDescription(
994 Locale.MustBeOfType(),
995 ErrorDetails{"key": STRING_SCHEMA, "type": TYPE_OBJECT},
996 ))
997 }
998
999 err = d.parseSchema(refdDocumentNode, newSchema)
1000 if err != nil {
1001 return err
1002 }
1003
1004 currentSchema.refSchema = newSchema
1005
1006 return nil
1007
1008 }
1009
1010 func (d *Schema) parseProperties(documentNode interface{}, currentSchema *subSchema) error {
1011
1012 if !isKind(documentNode, reflect.Map) {
1013 return errors.New(formatErrorDescription(
1014 Locale.MustBeOfType(),
1015 ErrorDetails{"key": STRING_PROPERTIES, "type": TYPE_OBJECT},
1016 ))
1017 }
1018
1019 m := documentNode.(map[string]interface{})
1020 for k := range m {
1021 schemaProperty := k
1022 newSchema := &subSchema{property: schemaProperty, parent: currentSchema, ref: currentSchema.ref}
1023 currentSchema.propertiesChildren = append(currentSchema.propertiesChildren, newSchema)
1024 err := d.parseSchema(m[k], newSchema)
1025 if err != nil {
1026 return err
1027 }
1028 }
1029
1030 return nil
1031 }
1032
1033 func (d *Schema) parseDependencies(documentNode interface{}, currentSchema *subSchema) error {
1034
1035 if !isKind(documentNode, reflect.Map) {
1036 return errors.New(formatErrorDescription(
1037 Locale.MustBeOfType(),
1038 ErrorDetails{"key": KEY_DEPENDENCIES, "type": TYPE_OBJECT},
1039 ))
1040 }
1041
1042 m := documentNode.(map[string]interface{})
1043 currentSchema.dependencies = make(map[string]interface{})
1044
1045 for k := range m {
1046 switch reflect.ValueOf(m[k]).Kind() {
1047
1048 case reflect.Slice:
1049 values := m[k].([]interface{})
1050 var valuesToRegister []string
1051
1052 for _, value := range values {
1053 if !isKind(value, reflect.String) {
1054 return errors.New(formatErrorDescription(
1055 Locale.MustBeOfType(),
1056 ErrorDetails{
1057 "key": STRING_DEPENDENCY,
1058 "type": STRING_SCHEMA_OR_ARRAY_OF_STRINGS,
1059 },
1060 ))
1061 }
1062 valuesToRegister = append(valuesToRegister, value.(string))
1063 currentSchema.dependencies[k] = valuesToRegister
1064 }
1065
1066 case reflect.Map, reflect.Bool:
1067 depSchema := &subSchema{property: k, parent: currentSchema, ref: currentSchema.ref}
1068 err := d.parseSchema(m[k], depSchema)
1069 if err != nil {
1070 return err
1071 }
1072 currentSchema.dependencies[k] = depSchema
1073
1074 default:
1075 return errors.New(formatErrorDescription(
1076 Locale.MustBeOfType(),
1077 ErrorDetails{
1078 "key": STRING_DEPENDENCY,
1079 "type": STRING_SCHEMA_OR_ARRAY_OF_STRINGS,
1080 },
1081 ))
1082 }
1083
1084 }
1085
1086 return nil
1087 }
1088
View as plain text