commonMain.io.konform.validation.jsonschema.JsonSchema.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of konform-jvm Show documentation
Show all versions of konform-jvm Show documentation
Konform: Portable validations for Kotlin
package io.konform.validation.jsonschema
import io.konform.validation.Constraint
import io.konform.validation.ValidationBuilder
import kotlin.math.roundToInt
public inline fun ValidationBuilder<*>.type(): Constraint<*> =
addConstraint(
"must be of the correct type",
) { it is T }
public fun ValidationBuilder.enum(vararg allowed: T): Constraint =
addConstraint(
"must be one of: {0}",
allowed.joinToString("', '", "'", "'"),
) { it in allowed }
public inline fun > ValidationBuilder.enum(): Constraint {
val enumNames = enumValues().map { it.name }
return addConstraint(
"must be one of: {0}",
enumNames.joinToString("', '", "'", "'"),
) { it in enumNames }
}
public fun ValidationBuilder.const(expected: T): Constraint =
addConstraint(
"must be {0}",
expected?.let { "'$it'" } ?: "null",
) { expected == it }
public fun ValidationBuilder.multipleOf(factor: Number): Constraint {
val factorAsDouble = factor.toDouble()
require(factorAsDouble > 0) { "multipleOf requires the factor to be strictly larger than 0" }
return addConstraint("must be a multiple of '{0}'", factor.toString()) {
val division = it.toDouble() / factorAsDouble
division.compareTo(division.roundToInt()) == 0
}
}
public fun ValidationBuilder.maximum(maximumInclusive: Number): Constraint =
addConstraint(
"must be at most '{0}'",
maximumInclusive.toString(),
) { it.toDouble() <= maximumInclusive.toDouble() }
public fun ValidationBuilder.exclusiveMaximum(maximumExclusive: Number): Constraint =
addConstraint(
"must be less than '{0}'",
maximumExclusive.toString(),
) { it.toDouble() < maximumExclusive.toDouble() }
public fun ValidationBuilder.minimum(minimumInclusive: Number): Constraint =
addConstraint(
"must be at least '{0}'",
minimumInclusive.toString(),
) { it.toDouble() >= minimumInclusive.toDouble() }
public fun ValidationBuilder.exclusiveMinimum(minimumExclusive: Number): Constraint =
addConstraint(
"must be greater than '{0}'",
minimumExclusive.toString(),
) { it.toDouble() > minimumExclusive.toDouble() }
public fun ValidationBuilder.minLength(length: Int): Constraint {
require(length >= 0) { IllegalArgumentException("minLength requires the length to be >= 0") }
return addConstraint(
"must have at least {0} characters",
length.toString(),
) { it.length >= length }
}
public fun ValidationBuilder.maxLength(length: Int): Constraint {
require(length >= 0) { IllegalArgumentException("maxLength requires the length to be >= 0") }
return addConstraint(
"must have at most {0} characters",
length.toString(),
) { it.length <= length }
}
public fun ValidationBuilder.pattern(pattern: String): Constraint = pattern(pattern.toRegex())
/** Enforces the string must be UUID hex format. */
public fun ValidationBuilder.uuid(): Constraint =
pattern("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$") hint "must be a valid UUID string"
public fun ValidationBuilder.pattern(pattern: Regex): Constraint =
addConstraint(
"must match the expected pattern",
pattern.toString(),
) { it.matches(pattern) }
public inline fun ValidationBuilder.minItems(minSize: Int): Constraint =
addConstraint(
"must have at least {0} items",
minSize.toString(),
) {
when (it) {
is Iterable<*> -> it.count() >= minSize
is Array<*> -> it.count() >= minSize
is Map<*, *> -> it.count() >= minSize
else -> throw IllegalStateException("minItems can not be applied to type ${T::class}")
}
}
public inline fun ValidationBuilder.maxItems(maxSize: Int): Constraint =
addConstraint(
"must have at most {0} items",
maxSize.toString(),
) {
when (it) {
is Iterable<*> -> it.count() <= maxSize
is Array<*> -> it.count() <= maxSize
is Map<*, *> -> it.count() <= maxSize
else -> throw IllegalStateException("maxItems can not be applied to type ${T::class}")
}
}
public inline fun > ValidationBuilder.minProperties(minSize: Int): Constraint =
minItems(minSize) hint "must have at least {0} properties"
public inline fun > ValidationBuilder.maxProperties(maxSize: Int): Constraint =
maxItems(maxSize) hint "must have at most {0} properties"
public inline fun ValidationBuilder.uniqueItems(unique: Boolean): Constraint =
addConstraint(
"all items must be unique",
) {
!unique ||
when (it) {
is Iterable<*> -> it.distinct().count() == it.count()
is Array<*> -> it.distinct().count() == it.count()
else -> throw IllegalStateException("uniqueItems can not be applied to type ${T::class}")
}
}