All Downloads are FREE. Search and download functionalities are using the official Maven repository.

androidMain.com.copperleaf.json.schema.JsonSchema.android.kt Maven / Gradle / Ivy

There is a newer version: 0.7.0
Show newest version
package com.copperleaf.json.schema

import com.copperleaf.json.pointer.JsonPointer
import com.copperleaf.json.pointer.toUriFragment
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.boolean
import kotlinx.serialization.json.booleanOrNull
import kotlinx.serialization.json.double
import kotlinx.serialization.json.doubleOrNull
import kotlinx.serialization.json.int
import kotlinx.serialization.json.intOrNull
import net.pwall.json.JSONArray
import net.pwall.json.JSONBoolean
import net.pwall.json.JSONDecimal
import net.pwall.json.JSONInteger
import net.pwall.json.JSONObject
import net.pwall.json.JSONString
import net.pwall.json.JSONValue
import net.pwall.json.schema.JSONSchema
import net.pwall.json.schema.output.BasicOutput
import net.pwall.json.schema.output.DetailedOutput
import net.pwall.json.schema.output.Output

public actual class JsonSchema actual constructor(input: String) {

    private val schema = JSONSchema.parse(input)

    public actual fun validate(element: JsonElement): SchemaValidationResult {
        return schema
            .validateDetailed(element.toJsonSchemaValue())
            .evaluateResults()
    }

    private fun DetailedOutput.evaluateResults(): SchemaValidationResult {
        return if (this.valid) {
            SchemaValidationResult.Valid
        } else {
            CustomInvalid(this)
        }
    }

    private class CustomInvalid(private val output: DetailedOutput) : SchemaValidationResult.Invalid() {
        override fun issues(pointer: JsonPointer): List {
            if (output.valid) return emptyList() // short-circuit for performance

            return buildList {
                output.getValidationErrorMessages(pointer.toUriFragment(), this)
            }
        }

        private fun Output.getValidationErrorMessages(
            pointer: String,
            listBuilder: MutableList,
        ) {
            when (this) {
                is BasicOutput -> this.getBasicValidationErrorMessages(pointer, listBuilder)
                is DetailedOutput -> this.getDetailedValidationErrorMessages(pointer, listBuilder)
                else -> {}
            }
        }

        private fun DetailedOutput.getDetailedValidationErrorMessages(
            pointer: String,
            listBuilder: MutableList,
        ) {
            if (this.valid) return // short-circuit for performance

            if (this.instanceLocation == pointer && this.errors.isNullOrEmpty()) {
                // we are a leaf output node, which has the actual validation message we need
                listBuilder.add(this.error ?: "")
            } else {
                this.errors?.forEach {
                    it.getValidationErrorMessages(pointer, listBuilder)
                }
            }
        }

        private fun BasicOutput.getBasicValidationErrorMessages(
            pointer: String,
            listBuilder: MutableList,
        ) {
            if (this.valid) return // short-circuit for performance
        }
    }

    private fun JsonElement.toJsonSchemaValue(): JSONValue? {
        return when (this) {
            is JsonPrimitive -> {
                if (this.booleanOrNull != null) {
                    JSONBoolean(boolean)
                } else if (this.intOrNull != null) {
                    JSONInteger(int)
                } else if (this.doubleOrNull != null) {
                    JSONDecimal(double.toBigDecimal())
                } else {
                    JSONString(content)
                }
            }
            is JsonNull -> null
            is JsonObject -> {
                JSONObject(this.mapValues { it.value.toJsonSchemaValue() })
            }
            is JsonArray -> {
                JSONArray(this.map { it.toJsonSchemaValue() })
            }
        }
    }

    public actual companion object {
        public actual fun parse(input: String): JsonSchema {
            return JsonSchema(input)
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy