-
Notifications
You must be signed in to change notification settings - Fork 8
/
contains.go
67 lines (57 loc) · 2.63 KB
/
contains.go
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package jsonschema
import "fmt"
// EvaluateContains checks if at least one element in an array meets the conditions specified by the 'contains' keyword.
// It follows the JSON Schema Draft 2020-12:
// - "contains" must be associated with a valid JSON Schema.
// - An array is valid if at least one of its elements matches the given schema, unless "minContains" is 0.
// - When "minContains" is 0, the array is considered valid even if no elements match the schema.
// - Produces annotations of indexes where the schema validates successfully.
// - If every element validates, it produces a boolean "true".
// - If the array is empty, annotations reflect the validation state.
// - Influences "unevaluatedItems" and may be used to implement "minContains" and "maxContains".
//
// This function provides detailed feedback on element validation and gathers comprehensive annotations.
//
// Reference: https://json-schema.org/draft/2020-12/json-schema-core#name-contains
func evaluateContains(schema *Schema, data []interface{}, evaluatedProps map[string]bool, evaluatedItems map[int]bool, dynamicScope *DynamicScope) ([]*EvaluationResult, *EvaluationError) {
if schema.Contains == nil {
// No 'contains' constraint is defined, skip further checks.
return nil, nil
}
results := []*EvaluationResult{}
var validCount int
for i, item := range data {
result, _, _ := schema.Contains.evaluate(item, dynamicScope)
if result != nil {
//nolint:errcheck
result.SetEvaluationPath("/contains").
SetSchemaLocation(schema.GetSchemaLocation("/contains")).
SetInstanceLocation(fmt.Sprintf("/%d", i))
if result.IsValid() {
validCount++
evaluatedItems[i] = true // Mark this item as evaluated
}
}
}
// Handle 'minContains' logic
minContains := 1 // Default value if 'minContains' is not specified
if schema.MinContains != nil {
minContains = int(*schema.MinContains)
}
if minContains == 0 && validCount == 0 {
// Valid scenario when minContains is 0. Still need to check maxContains.
} else if validCount < minContains {
return results, NewEvaluationError("minContains", "contains_too_few_items", "Value should contain at least {min_contains} matching items", map[string]interface{}{
"min_contains": minContains,
"count": validCount,
})
}
// Handle 'maxContains' logic
if schema.MaxContains != nil && validCount > int(*schema.MaxContains) {
return results, NewEvaluationError("maxContains", "contains_too_many_items", "Value should contain no more than {max_contains} matching items", map[string]interface{}{
"max_contains": *schema.MaxContains,
"count": validCount,
})
}
return results, nil
}