11package io.github.optimumcode.json.schema.internal.factories.array
22
33import io.github.optimumcode.json.schema.ErrorCollector
4+ import io.github.optimumcode.json.schema.internal.AnnotationKey
45import io.github.optimumcode.json.schema.internal.AssertionContext
5- import io.github.optimumcode.json.schema.internal.AssertionFactory
66import io.github.optimumcode.json.schema.internal.JsonSchemaAssertion
77import 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
810import kotlinx.serialization.json.JsonArray
911import kotlinx.serialization.json.JsonElement
10- import kotlinx.serialization.json.JsonObject
1112
1213@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()
2018 }
2119
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"
3227 }
33- itemsElement .mapIndexed { index, item -> itemsContext .at(index).schemaFrom(item) }
28+ element .mapIndexed { index, item -> context .at(index).schemaFrom(item) }
3429 } 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 ))
3732 }
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 )
4434 }
4535}
4636
47- private class ElementsAssertion (
37+ private class ItemsAssertion (
4838 private val items : List <JsonSchemaAssertion >,
4939 private val allElements : Boolean ,
50- private val additionalItems : JsonSchemaAssertion ? ,
5140) : JsonSchemaAssertion {
5241 init {
5342 if (allElements) {
@@ -61,36 +50,31 @@ private class ElementsAssertion(
6150 return if (allElements) {
6251 validateEachItem(element, context, errorCollector)
6352 } else {
64- validateWithAdditionalItems (element, context, errorCollector)
53+ validateElementsAtIndexes (element, context, errorCollector)
6554 }
6655 }
6756
68- private fun validateWithAdditionalItems (
57+ private fun validateElementsAtIndexes (
6958 element : JsonArray ,
7059 context : AssertionContext ,
7160 errorCollector : ErrorCollector ,
7261 ): Boolean {
7362 var valid = true
74- element.forEachIndexed { index, item ->
75- val result : Boolean
63+ var lastProcessedIndex = 0
64+ for ((index, item) in element.withIndex()) {
7665 if (index < items.size) {
77- result = items[index].validate(
66+ val result: Boolean = items[index].validate(
7867 item,
7968 context.at(index),
8069 errorCollector,
8170 )
71+ lastProcessedIndex = index
72+ valid = valid && result
8273 } else {
83- if (additionalItems == null ) {
84- return valid
85- }
86- result = additionalItems.validate(
87- item,
88- context.at(index),
89- errorCollector,
90- )
74+ break
9175 }
92- valid = valid && result
9376 }
77+ context.annotate(ItemsAssertionFactory .ANNOTATION , Result .Index (lastProcessedIndex))
9478 return valid
9579 }
9680
@@ -109,6 +93,7 @@ private class ElementsAssertion(
10993 )
11094 valid = valid && result
11195 }
96+ context.annotate(ItemsAssertionFactory .ANNOTATION , Result .All )
11297 return valid
11398 }
11499}
0 commit comments