1
1
package io.github.optimumcode.json.schema.internal.factories.array
2
2
3
3
import io.github.optimumcode.json.schema.ErrorCollector
4
+ import io.github.optimumcode.json.schema.internal.AnnotationKey
4
5
import io.github.optimumcode.json.schema.internal.AssertionContext
5
- import io.github.optimumcode.json.schema.internal.AssertionFactory
6
6
import io.github.optimumcode.json.schema.internal.JsonSchemaAssertion
7
7
import io.github.optimumcode.json.schema.internal.LoadingContext
8
+ import io.github.optimumcode.json.schema.internal.factories.AbstractAssertionFactory
9
+ import io.github.optimumcode.json.schema.internal.factories.array.ItemsAssertionFactory.Result
8
10
import kotlinx.serialization.json.JsonArray
9
11
import kotlinx.serialization.json.JsonElement
10
- import kotlinx.serialization.json.JsonObject
11
12
12
13
@Suppress(" unused" )
13
- internal object ItemsAssertionFactory : AssertionFactory {
14
- private const val itemsProperty: String = " items"
15
- private const val additionalItemsProperty: String = " additionalItems"
16
-
17
- override fun isApplicable (element : JsonElement ): Boolean {
18
- return element is JsonObject &&
19
- element.run { contains(itemsProperty) }
14
+ internal object ItemsAssertionFactory : AbstractAssertionFactory(" items" ) {
15
+ sealed class Result {
16
+ object All : Result()
17
+ class Index (val value : Int ) : Result()
20
18
}
21
19
22
- override fun create (element : JsonElement , context : LoadingContext ): JsonSchemaAssertion {
23
- require(element is JsonObject ) { " cannot extract properties from ${element::class .simpleName} " }
24
- val itemsElement: JsonElement = requireNotNull(element[itemsProperty]) {
25
- " cannot extract $itemsProperty property from element"
26
- }
27
- val itemsContext = context.at(itemsProperty)
28
- val itemsAssertions: List <JsonSchemaAssertion > = if (itemsElement is JsonArray ) {
29
- require(itemsElement.isNotEmpty()) { " $itemsProperty must have at least one element" }
30
- require(itemsElement.all(context::isJsonSchema)) {
31
- " all elements in $itemsProperty must be a valid JSON schema"
20
+ val ANNOTATION : AnnotationKey <Result > = AnnotationKey .create(property)
21
+
22
+ override fun createFromProperty (element : JsonElement , context : LoadingContext ): JsonSchemaAssertion {
23
+ val itemsAssertions: List <JsonSchemaAssertion > = if (element is JsonArray ) {
24
+ require(element.isNotEmpty()) { " $property must have at least one element" }
25
+ require(element.all(context::isJsonSchema)) {
26
+ " all elements in $property must be a valid JSON schema"
32
27
}
33
- itemsElement .mapIndexed { index, item -> itemsContext .at(index).schemaFrom(item) }
28
+ element .mapIndexed { index, item -> context .at(index).schemaFrom(item) }
34
29
} else {
35
- require(context.isJsonSchema(itemsElement )) { " $itemsProperty must be a valid JSON schema" }
36
- listOf (itemsContext .schemaFrom(itemsElement ))
30
+ require(context.isJsonSchema(element )) { " $property must be a valid JSON schema" }
31
+ listOf (context .schemaFrom(element ))
37
32
}
38
-
39
- val additionalItemsAssertion: JsonSchemaAssertion ? = element[additionalItemsProperty]?.let {
40
- require(context.isJsonSchema(it)) { " $additionalItemsProperty must be a valid JSON schema" }
41
- context.at(additionalItemsProperty).schemaFrom(it)
42
- }
43
- return ElementsAssertion (itemsAssertions, itemsElement !is JsonArray , additionalItemsAssertion)
33
+ return ItemsAssertion (itemsAssertions, element !is JsonArray )
44
34
}
45
35
}
46
36
47
- private class ElementsAssertion (
37
+ private class ItemsAssertion (
48
38
private val items : List <JsonSchemaAssertion >,
49
39
private val allElements : Boolean ,
50
- private val additionalItems : JsonSchemaAssertion ? ,
51
40
) : JsonSchemaAssertion {
52
41
init {
53
42
if (allElements) {
@@ -61,36 +50,31 @@ private class ElementsAssertion(
61
50
return if (allElements) {
62
51
validateEachItem(element, context, errorCollector)
63
52
} else {
64
- validateWithAdditionalItems (element, context, errorCollector)
53
+ validateElementsAtIndexes (element, context, errorCollector)
65
54
}
66
55
}
67
56
68
- private fun validateWithAdditionalItems (
57
+ private fun validateElementsAtIndexes (
69
58
element : JsonArray ,
70
59
context : AssertionContext ,
71
60
errorCollector : ErrorCollector ,
72
61
): Boolean {
73
62
var valid = true
74
- element.forEachIndexed { index, item ->
75
- val result : Boolean
63
+ var lastProcessedIndex = 0
64
+ for ((index, item) in element.withIndex()) {
76
65
if (index < items.size) {
77
- result = items[index].validate(
66
+ val result: Boolean = items[index].validate(
78
67
item,
79
68
context.at(index),
80
69
errorCollector,
81
70
)
71
+ lastProcessedIndex = index
72
+ valid = valid && result
82
73
} else {
83
- if (additionalItems == null ) {
84
- return valid
85
- }
86
- result = additionalItems.validate(
87
- item,
88
- context.at(index),
89
- errorCollector,
90
- )
74
+ break
91
75
}
92
- valid = valid && result
93
76
}
77
+ context.annotate(ItemsAssertionFactory .ANNOTATION , Result .Index (lastProcessedIndex))
94
78
return valid
95
79
}
96
80
@@ -109,6 +93,7 @@ private class ElementsAssertion(
109
93
)
110
94
valid = valid && result
111
95
}
96
+ context.annotate(ItemsAssertionFactory .ANNOTATION , Result .All )
112
97
return valid
113
98
}
114
99
}
0 commit comments