Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 2 additions & 17 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,8 @@ jobs:
version: latest
run_install: true
- run: pnpm why caniuse-lite electron-to-chromium node-releases
- run: cargo run -p generate-data
- run: cargo test

lint:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true
- uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }}
- run: cargo clippy --all-features
- run: cargo clippy --example inspect
- run: cargo clippy --tests
Expand All @@ -62,4 +46,5 @@ jobs:
with:
submodules: true
- run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- run: cargo run -p generate-data
- run: wasm-pack build --dev --target=web -- --features wasm_bindgen
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@
"**/bower_components": true,
"**/*.code-search": true,
"vendor/**": true
}
},
"rust-analyzer.files.excludeDirs": [
"src/generated"
]
}
28 changes: 7 additions & 21 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,7 @@ repository = "https://github.com/browserslist/browserslist-rs"
license = "MIT"
keywords = ["web", "javascript"]
categories = ["web-programming", "config"]
include = [
"**/*.rs",
"Cargo.toml",
"vendor/caniuse/fulldata-json/data-2.0.json",
"vendor/canisue/features-json/*.json",
"vendor/caniuse/region-usage-json/*.json",
"vendor/electron-to-chromium/versions.json",
"vendor/node-releases/data/**/*.json",
]
include = ["**/*.rs", "Cargo.toml", "src/generated/**/*.json"]

[lib]
name = "browserslist"
Expand All @@ -39,30 +31,24 @@ chrono = { version = "0.4.31", features = [
"clock",
"oldtime",
], default-features = false } # disable wasmbind by default
either = "1.9"
indexmap = { version = "2.1", features = ["serde"] }
itertools = "0.12"
either = "1.12"
indexmap = { version = "2.2", features = ["serde"] }
itertools = "0.13"
nom = "7.1"
once_cell = "1.19"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
string_cache = "0.8"
thiserror = "1.0"

[dev-dependencies]
clap = { version = "4.4", features = ["derive"] }
test-case = "3.3"

[build-dependencies]
anyhow = "1.0"
indexmap = { version = "2.1", features = ["serde"] }
quote = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
string_cache_codegen = "0.5.2"

[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2", optional = true }
js-sys = { version = "0.3", optional = true }
serde-wasm-bindgen = { version = "0.4", optional = true }
wasm-bindgen = { version = "0.2", optional = true }

[workspace]
members = [".", "generate-data"]
13 changes: 13 additions & 0 deletions generate-data/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "generate-data"
version = "0.1.0"
authors = ["Pig Fang <[email protected]>"]
edition = "2021"
publish = false

[dependencies]
anyhow = "1.0"
indexmap = { version = "2.1", features = ["serde"] }
quote = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
128 changes: 45 additions & 83 deletions build.rs → generate-data/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ use quote::quote;
use serde::{Deserialize, Serialize};
use std::{
collections::{BTreeMap, HashMap},
env, fs, io,
fs, io,
path::Path,
};

const OUT_DIR: &str = "src/generated";

fn encode_browser_name(name: &str) -> u8 {
match name {
"ie" => 1,
Expand Down Expand Up @@ -58,7 +60,6 @@ struct Feature {
}

fn main() -> Result<()> {
generate_browser_names_cache()?;
build_electron_to_chromium()?;
build_node_versions()?;
build_node_release_schedule()?;
Expand All @@ -68,30 +69,12 @@ fn main() -> Result<()> {
Ok(())
}

fn generate_browser_names_cache() -> Result<()> {
string_cache_codegen::AtomType::new(
"data::browser_name::BrowserNameAtom",
"browser_name_atom!",
)
.atoms(&[
"ie", "edge", "firefox", "chrome", "safari", "opera", "ios_saf", "op_mini", "android",
"bb", "op_mob", "and_chr", "and_ff", "ie_mob", "and_uc", "samsung", "and_qq", "baidu",
"kaios",
])
.write_to_file(&Path::new(&env::var("OUT_DIR")?).join("browser_name_atom.rs"))?;

Ok(())
}

fn build_electron_to_chromium() -> Result<()> {
println!("cargo:rerun-if-changed=vendor/electron-to-chromium/versions.json");

let path = format!("{}/electron-to-chromium.rs", env::var("OUT_DIR")?);
let path = format!("{OUT_DIR}/electron-to-chromium.rs");

let mut data = serde_json::from_slice::<BTreeMap<String, String>>(&fs::read(format!(
"{}/vendor/electron-to-chromium/versions.json",
env::var("CARGO_MANIFEST_DIR")?
))?)?
let mut data = serde_json::from_slice::<BTreeMap<String, String>>(&fs::read(
"vendor/electron-to-chromium/versions.json",
)?)?
.into_iter()
.map(|(electron_version, chromium_version)| {
(electron_version.parse::<f32>().unwrap(), chromium_version)
Expand Down Expand Up @@ -123,14 +106,10 @@ fn build_node_versions() -> Result<()> {
version: String,
}

println!("cargo:rerun-if-changed=vendor/node-releases/data/processed/envs.json");

let path = format!("{}/node-versions.rs", env::var("OUT_DIR")?);
let path = format!("{OUT_DIR}/node-versions.rs");

let releases: Vec<NodeRelease> = serde_json::from_slice(&fs::read(format!(
"{}/vendor/node-releases/data/processed/envs.json",
env::var("CARGO_MANIFEST_DIR")?
))?)?;
let releases: Vec<NodeRelease> =
serde_json::from_slice(&fs::read("vendor/node-releases/data/processed/envs.json")?)?;

let versions = releases.into_iter().map(|release| release.version);
fs::write(
Expand All @@ -145,22 +124,17 @@ fn build_node_versions() -> Result<()> {
}

fn build_node_release_schedule() -> Result<()> {
println!(
"cargo:rerun-if-changed=vendor/node-releases/data/release-schedule/release-schedule.json"
);

#[derive(Deserialize)]
struct NodeRelease {
start: String,
end: String,
}

let path = format!("{}/node-release-schedule.rs", env::var("OUT_DIR")?);
let path = format!("{OUT_DIR}/node-release-schedule.rs");

let schedule: HashMap<String, NodeRelease> = serde_json::from_slice(&fs::read(format!(
"{}/vendor/node-releases/data/release-schedule/release-schedule.json",
env::var("CARGO_MANIFEST_DIR")?
))?)?;
let schedule: HashMap<String, NodeRelease> = serde_json::from_slice(&fs::read(
"vendor/node-releases/data/release-schedule/release-schedule.json",
)?)?;
let cap = schedule.len();
let versions = schedule
.into_iter()
Expand All @@ -185,12 +159,10 @@ fn build_node_release_schedule() -> Result<()> {
}

fn build_caniuse_global() -> Result<()> {
let out_dir = env::var("OUT_DIR")?;

let data = parse_caniuse_global()?;

fs::write(
format!("{}/caniuse-browsers.rs", &out_dir),
format!("{OUT_DIR}/caniuse-browsers.rs"),
{
let map_cap = data.agents.len();
let browser_stat = data.agents.iter().map(|(name, agent)| {
Expand All @@ -211,14 +183,13 @@ fn build_caniuse_global() -> Result<()> {
}
});
quote! {
map.insert(BrowserNameAtom::from(#name), BrowserStat {
name: BrowserNameAtom::from(#name),
map.insert(#name, BrowserStat {
name: #name,
version_list: vec![#(#detail),*],
});
}
});
quote! {{
use ahash::AHashMap;
let mut map = AHashMap::with_capacity(#map_cap);
#(#browser_stat)*
map
Expand All @@ -235,7 +206,7 @@ fn build_caniuse_global() -> Result<()> {
(
usage,
quote! {
(BrowserNameAtom::from(#name), #version, #usage)
(#name, #version, #usage)
},
)
})
Expand All @@ -244,20 +215,20 @@ fn build_caniuse_global() -> Result<()> {
global_usage.sort_unstable_by(|(a, _), (b, _)| b.partial_cmp(a).unwrap());
let push_usage = global_usage.into_iter().map(|(_, tokens)| tokens);
fs::write(
format!("{}/caniuse-global-usage.rs", &out_dir),
format!("{OUT_DIR}/caniuse-global-usage.rs"),
quote! {
vec![#(#push_usage),*]
}
.to_string(),
)?;

let features_dir = format!("{}/features", &out_dir);
let features_dir = format!("{OUT_DIR}/features");
if matches!(fs::File::open(&features_dir), Err(e) if e.kind() == io::ErrorKind::NotFound) {
fs::create_dir(&features_dir)?;
}
for (name, feature) in &data.data {
fs::write(
format!("{}/{}.json", &features_dir, name),
format!("{features_dir}/{name}.json"),
serde_json::to_string(
&feature
.stats
Expand Down Expand Up @@ -290,15 +261,18 @@ fn build_caniuse_global() -> Result<()> {
use indexmap::IndexMap;
use once_cell::sync::Lazy;
use serde_json::from_str;
use crate::data::browser_name::BrowserNameAtom;
use crate::data::decode_browser_name;

type Stat = Lazy<AHashMap<&'static str, IndexMap<&'static str, u8>>>;
type Json = AHashMap::<u8, IndexMap<&'static str, u8>>;

match name {
#( #features => {
static STAT: Lazy<AHashMap<BrowserNameAtom, IndexMap<&'static str, u8>>> = Lazy::new(|| {
from_str::<AHashMap::<u8, IndexMap<&'static str, u8>>>(include_str!(concat!(env!("OUT_DIR"), "/features/", #features, ".json")))
static STAT: Stat = Lazy::new(|| {
from_str::<Json>(include_str!(concat!("features/", #features, ".json")))
.unwrap()
.into_iter()
.map(|(browser, versions)| (crate::data::browser_name::decode_browser_name(browser), versions))
.map(|(browser, versions)| (decode_browser_name(browser), versions))
.collect()
});
Some(&*STAT)
Expand All @@ -307,20 +281,17 @@ fn build_caniuse_global() -> Result<()> {
}
}};
fs::write(
format!("{}/caniuse-feature-matching.rs", &out_dir),
format!("{OUT_DIR}/caniuse-feature-matching.rs"),
tokens.to_string(),
)?;

Ok(())
}

fn parse_caniuse_global() -> Result<Caniuse> {
println!("cargo:rerun-if-changed=vendor/caniuse/fulldata-json/data-2.0.json");

Ok(serde_json::from_slice(&fs::read(format!(
"{}/vendor/caniuse/fulldata-json/data-2.0.json",
env::var("CARGO_MANIFEST_DIR")?
))?)?)
Ok(serde_json::from_slice(&fs::read(
"vendor/caniuse/fulldata-json/data-2.0.json",
)?)?)
}

fn build_caniuse_region() -> Result<()> {
Expand All @@ -329,25 +300,13 @@ fn build_caniuse_region() -> Result<()> {
data: HashMap<String, HashMap<String, Option<f32>>>,
}

let files = fs::read_dir(format!(
"{}/vendor/caniuse/region-usage-json",
env::var("CARGO_MANIFEST_DIR")?
))?
.map(|entry| entry.map_err(anyhow::Error::from))
.collect::<Result<Vec<_>>>()?;

files.iter().for_each(|entry| {
println!(
"cargo:rerun-if-changed=vendor/caniuse/region-usage-json/{}",
entry.file_name().into_string().unwrap()
)
});

let out_dir = env::var("OUT_DIR")?;
let files = fs::read_dir("vendor/caniuse/region-usage-json")?
.map(|entry| entry.map_err(anyhow::Error::from))
.collect::<Result<Vec<_>>>()?;

let Caniuse { agents, .. } = parse_caniuse_global()?;

let region_dir = format!("{}/region", &out_dir);
let region_dir = format!("{OUT_DIR}/region");
if matches!(fs::File::open(&region_dir), Err(e) if e.kind() == io::ErrorKind::NotFound) {
fs::create_dir(&region_dir)?;
}
Expand All @@ -370,7 +329,7 @@ fn build_caniuse_region() -> Result<()> {
.collect::<Vec<_>>();
usage.sort_unstable_by(|(_, _, a), (_, _, b)| b.partial_cmp(a).unwrap());
fs::write(
format!("{}/region/{}", &out_dir, file.file_name().to_str().unwrap()),
format!("{OUT_DIR}/region/{}", file.file_name().to_str().unwrap()),
serde_json::to_string(&usage)?,
)?;
}
Expand All @@ -389,15 +348,18 @@ fn build_caniuse_region() -> Result<()> {
let tokens = quote! {{
use once_cell::sync::Lazy;
use serde_json::from_str;
use crate::data::browser_name::BrowserNameAtom;
use crate::data::decode_browser_name;

type Usage = Lazy<Vec<(&'static str, &'static str, f32)>>;
type Json = Vec<(u8, &'static str, f32)>;

match region {
#( #regions => {
static USAGE: Lazy<Vec<(BrowserNameAtom, &'static str, f32)>> = Lazy::new(|| {
from_str::<Vec<(u8, &'static str, f32)>>(include_str!(concat!(env!("OUT_DIR"), "/region/", #regions, ".json")))
static USAGE: Usage = Lazy::new(|| {
from_str::<Json>(include_str!(concat!("region/", #regions, ".json")))
.unwrap()
.into_iter()
.map(|(browser, version, usage)| (crate::data::browser_name::decode_browser_name(browser), version, usage))
.map(|(browser, version, usage)| (decode_browser_name(browser), version, usage))
.collect()
});
Some(&*USAGE)
Expand All @@ -406,7 +368,7 @@ fn build_caniuse_region() -> Result<()> {
}
}};
fs::write(
format!("{}/caniuse-region-matching.rs", &out_dir),
format!("{OUT_DIR}/caniuse-region-matching.rs"),
tokens.to_string(),
)?;

Expand Down
Loading