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
14 changes: 9 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ repository = "https://github.com/browserslist/browserslist-rs"
license = "MIT"
keywords = ["web", "javascript"]
categories = ["web-programming", "config"]
include = ["**/*.rs", "Cargo.toml", "src/generated/**/*.json"]

[lib]
name = "browserslist"
Expand All @@ -18,12 +17,13 @@ crate-type = ["rlib"]
wasm_bindgen = ["chrono/wasmbind", "js-sys"]

[dependencies]
ahash = { version = "0.8.12", features = ["serde"] }
chrono = { version = "0.4.38", features = [
ahash = { workspace = true, features = ["serde"] }
browserslist-data = { version = "0.1.0", path = "data" }
chrono = { workspace = true, features = [
"std",
"clock",
"oldtime",
], default-features = false } # disable wasmbind by default
] } # disable wasmbind by default
either = "1.13"
itertools = "0.13"
nom = "7.1"
Expand All @@ -39,4 +39,8 @@ test-case = "3.3"
js-sys = { version = "0.3", optional = true }

[workspace]
members = [".", "generate-data", "wasm"]
members = [".", "data", "generate-data", "wasm"]

[workspace.dependencies]
ahash = "0.8.12"
chrono = { version = "0.4.38", default-features = false }
13 changes: 13 additions & 0 deletions data/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "browserslist-data"
version = "0.1.0"
authors = ["Pig Fang <g-plane@hotmail.com>"]
edition = "2024"
description = "Data for browserslist-rs."
repository = "https://github.com/browserslist/browserslist-rs"
license = "MIT"
include = ["**/*.rs", "Cargo.toml", "src/generated/**/*.bin", "src/generated/**/*.u32seq"]

[dependencies]
ahash = { workspace = true }
chrono = { workspace = true }
77 changes: 27 additions & 50 deletions src/data/caniuse.rs → data/src/caniuse.rs
Original file line number Diff line number Diff line change
@@ -1,41 +1,34 @@
use ahash::AHashMap;
use std::{
borrow::{Borrow, Cow},
fmt,
sync::LazyLock,
};
use std::{borrow::Cow, sync::LazyLock};

pub(crate) mod features;
pub(crate) mod region;
pub mod features;
pub mod region;

use crate::data::utils::BinMap;
use crate::utils::{BinMap, PooledStr};

pub const ANDROID_EVERGREEN_FIRST: f32 = 37.0;
pub const OP_MOB_BLINK_FIRST: u32 = 14;

#[derive(Clone, Debug)]
pub struct BrowserStat(u32, u32);

#[derive(Clone, Copy)]
pub struct PooledStr(u32);

#[derive(Clone, Debug)]
pub struct VersionDetail {
pub version: PooledStr,
version: PooledStr,
pub release_date: i64,
// Use bool instead of Option to use pad space
pub released: bool,
pub global_usage: f32,
}

include!("../generated/caniuse-browsers.rs");
include!("generated/caniuse-browsers.rs");

pub static CANIUSE_BROWSERS: BinMap<PooledStr, BrowserStat> = BinMap(BROWSERS_STATS);
static CANIUSE_BROWSERS: BinMap<PooledStr, BrowserStat> = BinMap(BROWSERS_STATS);

pub static CANIUSE_GLOBAL_USAGE: &[(PooledStr, PooledStr, f32)] =
include!("../generated/caniuse-global-usage.rs");
static CANIUSE_GLOBAL_USAGE: &[(PooledStr, PooledStr, f32)] =
include!("generated/caniuse-global-usage.rs");

pub static BROWSER_VERSION_ALIASES: LazyLock<
static BROWSER_VERSION_ALIASES: LazyLock<
AHashMap<&'static str, AHashMap<&'static str, &'static str>>,
> = LazyLock::new(|| {
let mut aliases = CANIUSE_BROWSERS
Expand Down Expand Up @@ -165,6 +158,17 @@ pub fn iter_browser_stat(
})
}

pub fn iter_global_usage() -> impl ExactSizeIterator<Item = (&'static str, &'static str, f32)> {
CANIUSE_GLOBAL_USAGE
.iter()
.copied()
.map(|(name, version, usage)| (name.as_str(), version.as_str(), usage))
}

pub fn get_browser_version_alias(name: &str, version: &str) -> Option<&'static str> {
BROWSER_VERSION_ALIASES.get(name)?.get(version).copied()
}

fn get_browser_alias(name: &str) -> &str {
match name {
"fx" | "ff" => "firefox",
Expand All @@ -182,7 +186,7 @@ fn get_browser_alias(name: &str) -> &str {
}
}

pub(crate) fn to_desktop_name(name: &str) -> Option<&'static str> {
pub fn to_desktop_name(name: &str) -> Option<&'static str> {
match name {
"and_chr" | "android" => Some("chrome"),
"and_ff" => Some("firefox"),
Expand All @@ -201,17 +205,14 @@ fn get_mobile_by_desktop_name(name: &str) -> &'static str {
}
}

pub(crate) fn normalize_version<'a>(
pub fn normalize_version<'a>(
name: &'a str,
version_list: &'static [VersionDetail],
version: &'a str,
) -> Option<&'a str> {
if version_list.iter().any(|v| v.version.as_str() == version) {
Some(version)
} else if let Some(version) = BROWSER_VERSION_ALIASES
.get(name)
.and_then(|aliases| aliases.get(version))
{
} else if let Some(version) = get_browser_version_alias(name, version) {
Some(version)
} else if version_list.len() == 1 {
version_list.first().map(|s| s.version.as_str())
Expand All @@ -227,32 +228,8 @@ impl BrowserStat {
}
}

impl PooledStr {
pub fn as_str(&self) -> &'static str {
static STRPOOL: &str = include_str!("../generated/caniuse-strpool.bin");

// 24bit offset and 8bit len
let offset = self.0 & ((1 << 24) - 1);
let len = self.0 >> 24;

&STRPOOL[(offset as usize)..][..(len as usize)]
}
}

impl Borrow<str> for PooledStr {
fn borrow(&self) -> &str {
self.as_str()
}
}

impl fmt::Display for PooledStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}

impl fmt::Debug for PooledStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
impl VersionDetail {
pub fn version(&self) -> &'static str {
self.version.as_str()
}
}
8 changes: 4 additions & 4 deletions src/data/caniuse/features.rs → data/src/caniuse/features.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::PooledStr;
use crate::data::{
use crate::{
decode_browser_name,
utils::{BinMap, PairU32, U32},
};
Expand All @@ -19,9 +19,9 @@ pub struct VersionList(PairU32);
// static FEATURES_STAT_FLAGS: &[u8]; // support flag
// static FEATURES_STAT_BROWSERS: &[u8]; // browser name id
// ```
include!("../../generated/caniuse-feature-matching.rs");
include!("../generated/caniuse-feature-matching.rs");

pub(crate) fn get_feature_stat(name: &str) -> Option<Feature> {
pub fn get_feature_stat(name: &str) -> Option<Feature> {
BinMap(FEATURES).get(name).copied()
}

Expand All @@ -46,7 +46,7 @@ impl Feature {

impl VersionList {
pub fn get(&self, version: &str) -> Option<u8> {
let range = (self.0 .0.get() as usize)..(self.0 .1.get() as usize);
let range = (self.0.0.get() as usize)..(self.0.1.get() as usize);
let index = FEATURES_STAT_VERSION_STORE[range.clone()]
.binary_search_by_key(&version, |s| PooledStr(s.get()).as_str())
.ok()?;
Expand Down
6 changes: 3 additions & 3 deletions src/data/caniuse/region.rs → data/src/caniuse/region.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::PooledStr;
use crate::data::{
use crate::{
decode_browser_name,
utils::{BinMap, U32},
};
Expand All @@ -14,9 +14,9 @@ pub struct RegionData(u32, u32);
// static REGIONS_VERSIONS: &[U32]; // version string
// static REGIONS_USAGES: &[U32]; // browser usage (f32)
// ```
include!("../../generated/caniuse-region-matching.rs");
include!("../generated/caniuse-region-matching.rs");

pub(crate) fn get_usage_by_region(region: &str) -> Option<RegionData> {
pub fn get_usage_by_region(region: &str) -> Option<RegionData> {
BinMap(REGIONS).get(region).copied()
}

Expand Down
17 changes: 1 addition & 16 deletions src/data/electron.rs → data/src/electron.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
use crate::error::Error;
use nom::{
character::complete::{char, u16},
combinator::{all_consuming, opt},
number::complete::float,
sequence::{pair, terminated},
};
use std::ops::Range;

include!("../generated/electron-to-chromium.rs");
include!("generated/electron-to-chromium.rs");

pub fn versions() -> impl ExactSizeIterator<Item = (f32, &'static str)> + DoubleEndedIterator {
ELECTRON_VERSIONS
Expand All @@ -33,11 +26,3 @@ pub fn bounded_range(range: Range<f32>) -> Result<&'static [&'static str], f32>

Ok(&CHROMIUM_VERSIONS[start..=end])
}

pub(crate) fn parse_version(version: &str) -> Result<f32, Error> {
all_consuming(terminated(float, opt(pair(char('.'), u16))))(version)
.map(|(_, v)| v)
.map_err(|_: nom::Err<nom::error::Error<_>>| {
Error::UnknownElectronVersion(version.to_string())
})
}
File renamed without changes.
6 changes: 3 additions & 3 deletions src/data/mod.rs → data/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub(crate) mod caniuse;
pub(crate) mod electron;
pub(crate) mod node;
pub mod caniuse;
pub mod electron;
pub mod node;
mod utils;

#[doc(hidden)]
Expand Down
4 changes: 2 additions & 2 deletions src/data/node.rs → data/src/node.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use chrono::NaiveDate;

include!("../generated/node-versions.rs");
include!("../generated/node-release-schedule.rs");
include!("generated/node-versions.rs");
include!("generated/node-release-schedule.rs");

pub fn versions() -> &'static [&'static str] {
NODE_VERSIONS
Expand Down
37 changes: 35 additions & 2 deletions src/data/utils.rs → data/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::borrow::Borrow;
use std::{borrow::Borrow, fmt};

pub struct BinMap<'a, K, V>(pub(super) &'a [(K, V)]);
pub(super) struct BinMap<'a, K, V>(pub(super) &'a [(K, V)]);

impl<K, V> BinMap<'_, K, V> {
pub fn get<Q>(&self, q: &Q) -> Option<&V>
Expand Down Expand Up @@ -43,3 +43,36 @@ impl U32 {
self.0.to_le()
}
}

#[derive(Clone, Copy)]
pub(super) struct PooledStr(pub(super) u32);

impl PooledStr {
pub fn as_str(&self) -> &'static str {
static STRPOOL: &str = include_str!("generated/caniuse-strpool.bin");

// 24bit offset and 8bit len
let offset = self.0 & ((1 << 24) - 1);
let len = self.0 >> 24;

&STRPOOL[(offset as usize)..][..(len as usize)]
}
}

impl Borrow<str> for PooledStr {
fn borrow(&self) -> &str {
self.as_str()
}
}

impl fmt::Display for PooledStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}

impl fmt::Debug for PooledStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
2 changes: 1 addition & 1 deletion generate-data/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{
io::{self, Write},
};

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

fn encode_browser_name(name: &str) -> u8 {
match name {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
"license": "MIT",
"repository": "https://github.com/browserslist/browserslist-rs",
"devDependencies": {
"browserslist": "^4.25.0"
"browserslist": "^4.25.1"
}
}
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ pub use {error::Error, opts::Opts, queries::Distrib};

#[cfg(not(target_arch = "wasm32"))]
mod config;
mod data;
mod error;
mod opts;
mod parser;
Expand Down
8 changes: 8 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,14 @@ pub(crate) fn parse_browserslist_query(input: &str) -> PResult<Vec<SingleQuery>>
)(input)
}

pub(crate) fn parse_electron_version(version: &str) -> Result<f32, crate::error::Error> {
all_consuming(terminated(float, opt(pair(char('.'), u16))))(version)
.map(|(_, v)| v)
.map_err(|_: nom::Err<nom::error::Error<_>>| {
crate::error::Error::UnknownElectronVersion(version.to_string())
})
}

#[cfg(test)]
mod tests {
use crate::{opts::Opts, test::run_compare};
Expand Down
7 changes: 2 additions & 5 deletions src/queries/browser_accurate.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use super::{Distrib, QueryResult};
use crate::{
data::caniuse::{get_browser_stat, normalize_version},
error::Error,
opts::Opts,
};
use crate::{error::Error, opts::Opts};
use browserslist_data::caniuse::{get_browser_stat, normalize_version};
use std::borrow::Cow;

pub(super) fn browser_accurate(name: &str, version: &str, opts: &Opts) -> QueryResult {
Expand Down
Loading