relux-runtime 0.6.0

Internal: runtime for Relux. No semver guarantees.
//! Embedded Svelte viewer bundle.
//!
//! The gzipped IIFE bundle is committed at `vendor/relux-viewer.js.gz`
//! and baked into the binary at compile time. The per-test `event.html`
//! emitter at `report::event_html` decompresses these bytes and inlines
//! them into a `<script>` tag alongside the test's `window.RELUX_DATA`
//! payload.
//!
//! The vendored artifact is regenerated by `just viewer-build`; a
//! pre-commit hook and CI step verify it stays in sync with the
//! `viewer/` sources.

/// Gzipped IIFE bundle bytes; identical to the file on disk at
/// `vendor/relux-viewer.js.gz` at compile time.
pub fn bundle_gz() -> &'static [u8] {
    include_bytes!("../../../vendor/relux-viewer.js.gz")
}

/// Gzipped highlight.js core bundle. Inlined into `event.html`
/// alongside the viewer bundle so the source pane can syntax-highlight
/// Relux code without a separate served asset.
pub fn hljs_gz() -> &'static [u8] {
    include_bytes!("../../../vendor/highlight-11.11.1.min.js.gz")
}

/// Gzipped bytes of `HLJS_RELUX_INIT` (the Relux hljs grammar). Computed
/// lazily once per process and cached. The raw source is committed at
/// `report/highlight-relux.js`; compressing at runtime avoids carrying a
/// separately-vendored `.gz` for an asset that already lives in-tree.
pub fn hljs_init_gz() -> &'static [u8] {
    use std::io::Write;
    use std::sync::OnceLock;

    use flate2::Compression;
    use flate2::write::GzEncoder;

    static CELL: OnceLock<Vec<u8>> = OnceLock::new();
    CELL.get_or_init(|| {
        let mut encoder = GzEncoder::new(Vec::new(), Compression::best());
        encoder
            .write_all(crate::report::hljs_init::HLJS_RELUX_INIT.as_bytes())
            .expect("write to Vec cannot fail");
        encoder.finish().expect("finish to Vec cannot fail")
    })
}

#[cfg(test)]
mod tests {
    use super::*;
    use flate2::read::GzDecoder;
    use std::io::Read;

    #[test]
    fn embedded_bundle_is_valid_gzip_with_expected_entry() {
        let bytes = bundle_gz();
        assert!(!bytes.is_empty(), "embedded bundle is empty");

        let mut decoder = GzDecoder::new(bytes);
        let mut js = String::new();
        decoder
            .read_to_string(&mut js)
            .expect("bundle is not valid gzip");

        // The bundle reads `window.RELUX_DATA` at mount time
        // (see viewer/src/main.ts). esbuild preserves this string as
        // a property access; if it disappears, the entry-point logic
        // has been replaced or the wrong artifact was embedded.
        assert!(
            js.contains("RELUX_DATA"),
            "decompressed bundle missing 'RELUX_DATA' entry hook"
        );
    }

    #[test]
    fn hljs_bundle_is_valid_gzip_with_register_language_hook() {
        let bytes = hljs_gz();
        assert!(!bytes.is_empty(), "hljs bundle is empty");

        let mut decoder = GzDecoder::new(bytes);
        let mut js = String::new();
        decoder
            .read_to_string(&mut js)
            .expect("hljs bundle is not valid gzip");

        // highlight.js exposes its API as `hljs` and includes
        // `registerLanguage`. If either is missing the wrong file is
        // vendored.
        assert!(
            js.contains("registerLanguage"),
            "decompressed hljs bundle missing 'registerLanguage' entry hook"
        );
    }
}