vite-static-shared 1.1.0

Shared code for vite-static
Documentation
#![warn(clippy::pedantic)]

use std::{borrow::Cow, collections::HashMap};

use serde::{Deserialize, Serialize};

pub mod parsing;

#[doc(hidden)]
#[path = "tests.rs"]
pub mod __tests;

/// Type of `.vite/manifest.json`.
pub type ViteManifest<'a> = HashMap<Cow<'a, str>, ManifestChunk<'a>>;

/// Dynamic boxed manifest.
///
/// Used as generic manifest to be plugged in integrations.
///
/// Created with [`Manifest::boxed()`] method.
///
/// ```rust
/// # use vite_static_shared::__tests::*;
/// #
/// MyViteStatic.boxed();
/// ```
pub type DynManifest<'a> = Box<dyn Manifest<'a> + Send + Sync>;

/// Vite manifest chunk.
///
/// [See Vite documentation](https://vite.dev/guide/backend-integration)
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq, Hash)]
#[serde(rename_all = "camelCase")]
pub struct ManifestChunk<'a> {
    /// The key of this chunk in manifest.
    ///
    /// This field is added by `vite-static` and skipped during (de)serialization.
    #[serde(skip)]
    pub key: Cow<'a, str>,

    /// The contents of manifest chunk.
    ///
    /// This field is added by `vite-static` and skipped during (de)serialization.
    #[serde(skip)]
    pub contents: Cow<'a, [u8]>,

    /// [BLAKE3](https://github.com/BLAKE3-team/BLAKE3) hash of this chunk.
    ///
    /// BLAKE3 is used, because it's simple and fast.
    ///
    /// This field is added by `vite-static` and skipped during (de)serialization.
    #[serde(skip)]
    pub hash: Cow<'a, str>,

    /// Mime type of this chunk.
    ///
    /// This field is added by `vite-static` and skipped during (de)serialization.
    #[serde(skip)]
    pub mime_type: Cow<'a, str>,

    /// The input file name of this chunk/asset if known.
    pub src: Option<Cow<'a, str>>,

    /// The output file name of this chunk/asset.
    pub file: Cow<'a, str>,

    /// The list of CSS files imported by this chunk.
    #[serde(default)]
    pub css: Cow<'a, [Cow<'a, str>]>,

    /// The list of asset files imported by this chunk, excluding CSS files.
    #[serde(default)]
    pub assets: Cow<'a, [Cow<'a, str>]>,

    /// Whether this chunk or asset is an entry point
    #[serde(default)]
    pub is_entry: bool,

    /// The name of this chunk/asset if known.
    pub name: Option<Cow<'a, str>>,

    /// Whether this chunk is a dynamic entry point
    ///
    /// This field is only present in JS chunks.
    #[serde(default)]
    pub is_dynamic_entry: bool,

    /// The list of statically imported chunks by this chunk
    ///
    /// The values are the keys of the manifest. This field is only present in JS chunks.
    #[serde(default)]
    pub imports: Cow<'a, [Cow<'a, str>]>,

    /// The list of dynamically imported chunks by this chunk
    ///
    /// The values are the keys of the manifest. This field is only present in JS chunks.
    #[serde(default)]
    pub dynamic_imports: Cow<'a, [Cow<'a, str>]>,
}

/// Trait, that helps query chunks in Vite manifest.
///
/// See [`Manifest` derive](https://docs.rs/vite-static/latest/vite_static/derive.Manifest.html)
/// and [`ManifestChunk`].
pub trait Manifest<'a> {
    /// Returns generic boxed manifest.
    ///
    /// Usually used in integrations and functions, that require [`Manifest`].
    fn boxed(&self) -> DynManifest<'a>;

    /// Get base URL of [`Manifest`]. By default, it's `/`.
    ///
    /// Base URL - is an prefix before paths. This option is usually used in framework integrations
    /// and `HtmlIntegration`.
    fn base(&self) -> Cow<'a, str>;

    /// Get `output_filename` from manifest key.
    ///
    /// ```
    /// # use vite_static_shared::__tests::*;
    /// #
    /// assert_eq!(MyViteStatic.resolve_output("src/main.tsx").unwrap(), "main.HASH.js");
    /// ```
    fn resolve_output(&self, key: &str) -> Option<Cow<'a, str>>;

    /// Iterator over manifest keys (AKA input filenames, e.g. "src/main.tsx").
    ///
    /// ```
    /// # use vite_static_shared::__tests::*;
    /// #
    /// MyViteStatic.iter_keys();
    /// // returns iterator over keys (e.g. "src/main.tsx", "src/style.scss", "_shared.HASH.js", ...)
    /// ```
    fn iter_keys(&self) -> Box<dyn Iterator<Item = &str> + '_>;

    /// Iterator over manifest outputs (AKA output filenames, e.g. "main.HASH.js").
    ///
    /// ```
    /// # use vite_static_shared::__tests::*;
    /// #
    /// MyViteStatic.iter_outputs();
    /// // returns iterator over output filenames (e.g. "main.HASH.js", "chunks/_shared.HASH.js", ...)
    /// ```
    fn iter_outputs(&self) -> Box<dyn Iterator<Item = &str> + '_>;

    /// Get [`ManifestChunk`] from output filename.
    ///
    /// ```
    /// # use vite_static_shared::__tests::*;
    /// #
    /// let chunk = MyViteStatic.chunk("main.HASH.js").unwrap(); // returns Option<ManifestChunk>
    ///
    /// assert_eq!(chunk.key, "src/main.tsx");
    /// assert_eq!(chunk.file, "main.HASH.js");
    /// ```
    fn chunk(&self, output: &str) -> Option<Cow<'a, ManifestChunk<'a>>>;

    /// Get [`ManifestChunk`] from manifest key.
    ///
    /// ```rust
    /// # use vite_static_shared::__tests::*;
    /// #
    /// let chunk = MyViteStatic.chunk_by_key("src/main.tsx").unwrap(); // returns Option<ManifestChunk>
    ///
    /// assert_eq!(chunk.key, "src/main.tsx");
    /// assert_eq!(chunk.file, "main.HASH.js");
    /// ```
    fn chunk_by_key(&self, key: &str) -> Option<Cow<'a, ManifestChunk<'a>>> {
        match self.resolve_output(key) {
            Some(output) => self.chunk(&output),
            None => None,
        }
    }
}