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

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