yewprint_css/
lib.rs

1use anyhow::{bail, Context, Result};
2use serde::Deserialize;
3use std::path::Path;
4
5const LATEST_BLUEPRINT_WORKING_VERSION: &str = "3.54.0";
6
7pub const BLUEPRINT_CSS: &str = include_str!("blueprint.css");
8
9/// Download the CSS of Blueprint to a provided destination path.
10pub fn download_css(dest: impl AsRef<Path>) -> Result<()> {
11    let version = download_from_npm_package(
12        "@blueprintjs/core",
13        LATEST_BLUEPRINT_WORKING_VERSION,
14        Path::new("package/lib/css/blueprint.css"),
15        dest,
16    )
17    .context("while downloading CSS of @blueprintjs/core")?;
18    log::info!("Blueprint CSS updated to: {}", version);
19    Ok(())
20}
21
22/// Download any file from NPM package's latest version.
23pub fn download_from_npm_package(
24    package_name: &str,
25    version: &str,
26    src: impl AsRef<Path>,
27    dest: impl AsRef<Path>,
28) -> Result<String> {
29    let src = src.as_ref();
30    let dest = dest.as_ref();
31
32    let version = if version.is_empty() || version == "latest" {
33        let info: PackageInfo =
34            ureq::get(format!("https://registry.npmjs.org/{}", package_name).as_str())
35                .call()?
36                .into_json()?;
37
38        info.dist_tags.latest
39    } else {
40        version.to_string()
41    };
42
43    let resp = ureq::get(
44        format!(
45            "https://registry.npmjs.org/{}/-/{}-{}.tgz",
46            package_name,
47            package_name
48                .split_once('/')
49                .map(|(_, name)| name)
50                .unwrap_or(package_name),
51            version,
52        )
53        .as_str(),
54    )
55    .call()?;
56
57    let mut archive = tar::Archive::new(flate2::read::GzDecoder::new(resp.into_reader()));
58
59    let blueprint_css = archive.entries()?.find(|entry| {
60        entry
61            .as_ref()
62            .ok()
63            .and_then(|entry| entry.path().map(|path| path == src).ok())
64            .unwrap_or(false)
65    });
66
67    if let Some(entry) = blueprint_css {
68        let mut entry = entry.unwrap();
69        entry.unpack(dest)?;
70        Ok(version)
71    } else {
72        bail!("could not find `{}` in archive!", src.display());
73    }
74}
75
76#[derive(Deserialize)]
77struct PackageInfo {
78    #[serde(rename = "dist-tags")]
79    dist_tags: PackageDistTags,
80}
81
82#[derive(Deserialize)]
83struct PackageDistTags {
84    latest: String,
85}