jsMain.internal.CommonSchemaProps.kt Maven / Gradle / Ivy
package pt.lightweightform.lfkotlin.internal
import pt.lightweightform.lfkotlin.AllowedValues
import pt.lightweightform.lfkotlin.AsyncAllowedValues
import pt.lightweightform.lfkotlin.AsyncBound
import pt.lightweightform.lfkotlin.AsyncIsRequired
import pt.lightweightform.lfkotlin.AsyncStateProperty
import pt.lightweightform.lfkotlin.AsyncValidation
import pt.lightweightform.lfkotlin.Bound
import pt.lightweightform.lfkotlin.ComputedValue
import pt.lightweightform.lfkotlin.Context
import pt.lightweightform.lfkotlin.InitialValue
import pt.lightweightform.lfkotlin.IsRequired
import pt.lightweightform.lfkotlin.Schema
import pt.lightweightform.lfkotlin.StateProperty
import pt.lightweightform.lfkotlin.Storage
import pt.lightweightform.lfkotlin.StorageContextFn
import pt.lightweightform.lfkotlin.SyncAllowedValues
import pt.lightweightform.lfkotlin.SyncBound
import pt.lightweightform.lfkotlin.SyncIsRequired
import pt.lightweightform.lfkotlin.SyncStateProperty
import pt.lightweightform.lfkotlin.SyncValidation
import pt.lightweightform.lfkotlin.Validation
@Suppress("UNCHECKED_CAST", "UNCHECKED_CAST_TO_EXTERNAL_INTERFACE")
internal fun > addCommonPropsToSchema(
schema: S,
type: String,
isNullable: Boolean,
initialValue: T?,
computedInitialValue: InitialValue?,
computedValue: ComputedValue?,
isClientOnly: Boolean?,
isRequired: Boolean?,
computedIsRequired: IsRequired?,
isRequiredCode: String?,
allowedValues: List?,
computedAllowedValues: AllowedValues?,
disallowedValueCode: String?,
validations: List>?,
initialState: Map?,
extra: Map?
): S {
schema.type = type
schema.isNullable = if (isNullable) true else undefined
schema.initialValue =
when {
initialValue != null -> ktToJsValue(schema as Schema, initialValue)
computedInitialValue != null -> toStorageInitialValue(schema, computedInitialValue)
else -> undefined
}
schema.computedValue =
if (computedValue != null) toStorageComputedValue(schema, computedValue) else undefined
schema.isClientOnly = isClientOnly ?: undefined
schema.isRequired =
when {
isRequired != null -> isRequired
computedIsRequired != null -> toStorageIsRequired(computedIsRequired)
else -> undefined
}
schema.isRequiredCode = isRequiredCode ?: undefined
schema.allowedValues =
when {
allowedValues != null ->
allowedValues
.map { value -> ktToJsValue(schema as Schema, value) }
.toTypedArray()
computedAllowedValues != null -> toStorageAllowedValues(schema, computedAllowedValues)
else -> undefined
}
schema.disallowedValueCode = disallowedValueCode ?: undefined
schema.validate = validations?.map { toStorageValidation(it) }?.toTypedArray() ?: undefined
schema.initialState =
initialState?.let {
val state = js("{}")
for ((stateProp, stateVal) in it) {
state[stateProp] =
if (stateVal is StateProperty<*>) toStorageStateProperty(stateVal) else stateVal
}
state
}
?: undefined
if (extra != null) {
for ((prop, value) in extra) {
schema.asDynamic()[prop] = value
}
}
return schema
}
/** Converts an initial value into a "storage initial value" as expected by the `Storage`. */
internal fun toStorageInitialValue(
schema: Schema,
initialValue: InitialValue
): StorageContextFn = { storage: Storage ->
@Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE", "UNCHECKED_CAST")
initialValue.run { ktToJsValue(schema as Schema, Context(storage).initialValue()) }
}
/** Converts a computed value into a "storage computed value" as expected by the `Storage`. */
internal fun toStorageComputedValue(
schema: Schema,
computedValue: ComputedValue
): StorageContextFn = { storage: Storage ->
computedValue.run {
@Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE", "UNCHECKED_CAST")
ktToJsValue(schema as Schema, Context(storage).compute())
}
}
/** Converts a validation into a "storage validation" as expected by the `Storage`. */
@Suppress("UNCHECKED_CAST")
internal fun toStorageValidation(validation: Validation): StorageContextFn =
{ storage: Storage ->
val ctx = Context(storage)
when (validation) {
is SyncValidation ->
validation.run { ctx.validate(ctx.get(".")).toList().toTypedArray() }
is AsyncValidation ->
validation.run { ctx.validate(ctx.get(".")).then { it.toList().toTypedArray() } }
else -> error("Unsupported `Validation` implementation")
}
}
/**
* Converts an "is required" validation into a "storage is required validation" as expected by the
* `Storage`.
*/
internal fun toStorageIsRequired(isRequired: IsRequired): StorageContextFn = { storage: Storage ->
@Suppress("UNCHECKED_CAST")
when (isRequired) {
is SyncIsRequired -> isRequired.run { Context(storage).isRequired() }
is AsyncIsRequired -> isRequired.run { Context(storage).isRequired() }
else -> error("Unsupported `IsRequired` implementation")
}
}
/**
* Converts an "allowed values" validation into a "storage allowed values validation" as expected by
* the `Storage`.
*/
internal fun toStorageAllowedValues(
schema: Schema,
allowedValues: AllowedValues
): StorageContextFn = { storage: Storage ->
@Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE", "UNCHECKED_CAST")
when (allowedValues) {
is SyncAllowedValues ->
allowedValues.run {
Context(storage)
.allowedValues()
?.map { value -> ktToJsValue(schema as Schema, value) }
?.toTypedArray()
?: undefined
}
is AsyncAllowedValues ->
allowedValues.run {
Context(storage).allowedValues().then {
it?.map { value -> ktToJsValue(schema as Schema, value) }?.toTypedArray()
?: undefined
}
}
else -> error("Unsupported `AllowedValues` implementation")
}
}
/** Converts a "bound" validation into a "storage bound validation" as expected by the `Storage`. */
internal fun toStorageBound(bound: Bound): StorageContextFn = { storage: Storage ->
@Suppress("UNCHECKED_CAST")
when (bound) {
is SyncBound -> bound.run { Context(storage).bound() ?: undefined }
is AsyncBound -> bound.run { Context(storage).bound().then { it ?: undefined } }
else -> error("Unsupported `Bound` implementation")
}
}
/**
* Converts a "bound" validation into a "storage bound validation" as expected by the `Storage`.
* Coerces the bound to `minValue..maxValue`.
*/
internal fun > toStorageCoercedBound(
bound: Bound,
minValue: T?,
maxValue: T?,
): StorageContextFn = { storage: Storage ->
@Suppress("UNCHECKED_CAST")
when (bound) {
is SyncBound ->
bound.run { Context(storage).bound()?.coerceIn(minValue, maxValue) ?: undefined }
is AsyncBound ->
bound.run {
Context(storage).bound().then { it?.coerceIn(minValue, maxValue) ?: undefined }
}
else -> error("Unsupported `Bound` implementation")
}
}
/**
* Converts a "state property" object into a "storage bound state property" as expected by the
* `Storage`.
*/
internal fun toStorageStateProperty(stateProperty: StateProperty): StorageContextFn =
{ storage: Storage ->
@Suppress("UNCHECKED_CAST")
when (stateProperty) {
is SyncStateProperty -> stateProperty.run { Context(storage).property() }
is AsyncStateProperty -> stateProperty.run { Context(storage).property() }
else -> error("Unsupported `StateProperty` implementation")
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy