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

org.http4k.lens.datastarExtensions.kt Maven / Gradle / Ivy

package org.http4k.lens

import org.http4k.core.Body
import org.http4k.core.ContentType
import org.http4k.core.ContentType.Companion.TEXT_EVENT_STREAM
import org.http4k.core.Response
import org.http4k.core.with
import org.http4k.datastar.DatastarEvent
import org.http4k.datastar.DatastarEvent.Companion.from
import org.http4k.datastar.DatastarEvent.MergeFragments
import org.http4k.datastar.Fragment
import org.http4k.datastar.MergeMode
import org.http4k.datastar.MergeMode.morph
import org.http4k.datastar.Selector
import org.http4k.datastar.SettleDuration
import org.http4k.datastar.SettleDuration.Companion.DEFAULT
import org.http4k.sse.SseMessage
import org.http4k.sse.SseMessage.Event
import org.http4k.urlDecoded
import org.http4k.urlEncoded

// Present on all Datastar requests
val Header.DATASTAR_REQUEST get() = Header.boolean().defaulted("datastar_request", false)

// Special content type used for datastar events
val Header.DATASTAR_CONTENT_TYPE
    get() = Header.map(::ContentType, ContentType::toHeaderValue).required("content_type")

// Used for Datastae model data when a request is a GET
val Query.DATASTAR_MODEL get() = Query.map(String::urlDecoded, String::urlEncoded).optional("datastar")

/**
 * Put datastar event into response as a datastar-merge-fragments event
 */
fun Response.datastarFragments(
    vararg fragments: String,
    mergeMode: MergeMode = morph,
    selector: Selector? = null,
    useViewTransition: Boolean = false,
    settleDuration: SettleDuration? = DEFAULT,
    id: String? = null,
): Response = datastarFragments(fragments.toList(), mergeMode, selector, useViewTransition, settleDuration, id)

/**
 * Put datastar event into response as a datastar-merge-fragments event
 */
@JvmName("datastarFragmentsStrings")
fun Response.datastarFragments(
    fragments: List,
    mergeMode: MergeMode = morph,
    selector: Selector? = null,
    useViewTransition: Boolean = false,
    settleDuration: SettleDuration? = DEFAULT,
    id: String? = null,
): Response =
    datastarFragments(fragments.map { Fragment.of(it) }, mergeMode, selector, useViewTransition, settleDuration, id)

/**
 * Put datastar event into response as a datastar-merge-fragments event
 */
fun Response.datastarFragments(
    vararg fragments: Fragment,
    mergeMode: MergeMode = morph,
    selector: Selector? = null,
    useViewTransition: Boolean = false,
    settleDuration: SettleDuration? = DEFAULT,
    id: String? = null,
): Response = datastarFragments(
    MergeFragments(
        fragments.toList(),
        mergeMode,
        selector,
        useViewTransition,
        settleDuration,
        id
    )
)

/**
 * Put datastar event into response as a datastar-merge-fragments event
 */
@JvmName("datastarFragments")
fun Response.datastarFragments(
    fragments: List,
    mergeMode: MergeMode = morph,
    selector: Selector? = null,
    useViewTransition: Boolean = false,
    settleDuration: SettleDuration? = DEFAULT,
    id: String? = null,
): Response = datastarFragments(
    MergeFragments(
        fragments.toList(),
        mergeMode,
        selector,
        useViewTransition,
        settleDuration,
        id
    )
)

/**
 * Inject a Datastar Event into a response
 */
fun Response.datastarFragments(event: MergeFragments) = with(Body.datastarEvents().toLens() of listOf(event))

/**
 * Inject a Datastar MergeFragments event into a Response as a Datastar event
 */
fun Response.html(vararg events: MergeFragments) = html(events.flatMap { it.fragments }.joinToString("\n") { it.value })

/**
 * Roundtrip datastar events
 */
fun Body.Companion.datastarEvents() = string(TEXT_EVENT_STREAM)
    .map({ it.toDatastarEvents() }, { it.joinToString("") { it.toSseEvent().toMessage() } })

fun Body.Companion.datastarFragments(): BiDiBodyLensSpec> =
    datastarEvents().map({ it.filterIsInstance() }, { it })

fun Response.datastarEvents(events: List) =
    contentType(TEXT_EVENT_STREAM).body(events.joinToString("") { it.toSseEvent().toMessage() })

/**
 * Extract the datastarEvents
 */
fun Response.datastarEvents() = bodyString().toDatastarEvents()

private fun String.toDatastarEvents() = split("\n\n")
    .filter(String::isNotEmpty)
    .map { SseMessage.parse(it) }
    .filterIsInstance()
    .map(::from)




© 2015 - 2025 Weber Informatics LLC | Privacy Policy