workers-rsx 0.1.0

A JSX-like templating engine for Cloudflare Workers
Documentation
use serde::{de::DeserializeOwned, Serialize};

/// Decode a state value from a JSON string.
pub fn decode_state<T: DeserializeOwned>(json: &str) -> Option<T> {
    serde_json::from_str(json).ok()
}

/// Returns a `<script type="application/json">` block with the serialized state,
/// plus a listener script that reads it and includes `_state` in every htmx request.
/// Used on the initial full-page render.
pub(crate) fn state_init_script<T: Serialize>(state: &T) -> String {
    let json = serde_json::to_string(state).expect("state must be serializable");
    format!(
        "<script id=\"_state\" type=\"application/json\">{}</script>\
         <script>\
         document.addEventListener('htmx:configRequest',function(e){{\
         var el=document.getElementById('_state');\
         if(el)e.detail.parameters['_state']=el.textContent}})\
         </script>",
        json
    )
}

/// Returns an OOB-swappable `<script type="application/json">` block
/// that replaces the state in the DOM. Used in htmx diff responses.
pub(crate) fn state_update_script<T: Serialize>(state: &T) -> String {
    let json = serde_json::to_string(state).expect("state must be serializable");
    format!(
        "<script id=\"_state\" type=\"application/json\" hx-swap-oob=\"true\">{}</script>",
        json
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde::{Deserialize, Serialize};

    #[derive(Debug, PartialEq, Serialize, Deserialize)]
    struct TestState {
        count: u32,
        name: String,
    }

    #[test]
    fn round_trip() {
        let state = TestState {
            count: 42,
            name: "hello world".to_string(),
        };
        let json = serde_json::to_string(&state).unwrap();
        let decoded: TestState = decode_state(&json).unwrap();
        assert_eq!(state, decoded);
    }
}