Skip to content

Commit

Permalink
fix feature support queries with "mobile to desktop"
Browse files Browse the repository at this point in the history
  • Loading branch information
g-plane committed Jan 25, 2024
1 parent 65e248e commit 4233e1f
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 17 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ chrono = { version = "0.4.31", features = [
"oldtime",
], default-features = false } # disable wasmbind by default
either = "1.9"
indexmap = { version = "2.1", features = ["serde"] }
itertools = "0.12"
nom = "7.1"
once_cell = "1.19"
Expand All @@ -55,6 +56,7 @@ 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"
Expand Down
35 changes: 25 additions & 10 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use anyhow::Result;
use indexmap::IndexMap;
use quote::quote;
use serde::{Deserialize, Serialize};
use std::{
Expand Down Expand Up @@ -53,7 +54,7 @@ struct VersionDetail {

#[derive(Deserialize)]
struct Feature {
stats: HashMap<String, HashMap<String, String>>,
stats: HashMap<String, IndexMap<String, String>>,
}

fn main() -> Result<()> {
Expand Down Expand Up @@ -223,29 +224,43 @@ fn build_caniuse_global() -> Result<()> {
&feature
.stats
.iter()
.flat_map(|(name, versions)| {
versions
.iter()
.filter(|(_, stat)| stat.starts_with('y') || stat.starts_with('a'))
.map(|(version, _)| (encode_browser_name(name), version.clone()))
.map(|(name, versions)| {
(
encode_browser_name(name),
versions
.into_iter()
.map(|(version, flags)| {
let mut bit = 0;
if flags.contains('y') {
bit |= 1;
}
if flags.contains('a') {
bit |= 2;
}
(version, bit)
})
.collect::<IndexMap<_, u8>>(),
)
})
.collect::<Vec<_>>(),
.collect::<HashMap<_, _>>(),
)?,
)?;
}
let features = data.data.keys().collect::<Vec<_>>();
let tokens = quote! {{
use ahash::AHashMap;
use indexmap::IndexMap;
use once_cell::sync::Lazy;
use serde_json::from_str;
use crate::data::browser_name::BrowserNameAtom;

match name {
#( #features => {
static STAT: Lazy<Vec<(BrowserNameAtom, &'static str)>> = Lazy::new(|| {
from_str::<Vec<(u8, &'static str)>>(include_str!(concat!(env!("OUT_DIR"), "/features/", #features, ".json")))
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")))
.unwrap()
.into_iter()
.map(|(browser, version)| (crate::data::browser_name::decode_browser_name(browser), version))
.map(|(browser, versions)| (crate::data::browser_name::decode_browser_name(browser), versions))
.collect()
});
Some(&*STAT)
Expand Down
2 changes: 1 addition & 1 deletion src/data/caniuse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ fn get_browser_alias(name: &str) -> &str {
}
}

fn to_desktop_name(name: &str) -> Option<&'static str> {
pub(crate) fn to_desktop_name(name: &str) -> Option<&'static str> {
match name {
"and_chr" | "android" => Some("chrome"),
"and_ff" => Some("firefox"),
Expand Down
4 changes: 3 additions & 1 deletion src/data/caniuse/features.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use super::BrowserNameAtom;
use ahash::AHashMap;
use indexmap::IndexMap;

type Feature = Vec<(BrowserNameAtom, &'static str)>;
type Feature = AHashMap<BrowserNameAtom, IndexMap<&'static str, u8>>;

pub(crate) fn get_feature_stat(name: &str) -> Option<&'static Feature> {
include!(concat!(env!("OUT_DIR"), "/caniuse-feature-matching.rs"))
Expand Down
2 changes: 1 addition & 1 deletion src/queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ pub fn query(atom: QueryAtom, opts: &Opts) -> QueryResult {
coverage,
stats: Stats::Region(region),
} => cover_by_region::cover_by_region(coverage, region),
QueryAtom::Supports(name) => supports::supports(name),
QueryAtom::Supports(name) => supports::supports(name, opts),
QueryAtom::Electron(VersionRange::Bounded(from, to)) => {
electron_bounded_range::electron_bounded_range(from, to)
}
Expand Down
61 changes: 57 additions & 4 deletions src/queries/supports.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,65 @@
use super::{Distrib, QueryResult};
use crate::{data::caniuse::features::get_feature_stat, error::Error};
use crate::{
data::{
browser_name::BrowserNameAtom,
caniuse::{features::get_feature_stat, get_browser_stat, to_desktop_name, VersionDetail},
},
error::Error,
Opts,
};

pub(super) fn supports(name: &str) -> QueryResult {
const Y: u8 = 1;
const A: u8 = 2;

pub(super) fn supports(name: &str, opts: &Opts) -> QueryResult {
if let Some(feature) = get_feature_stat(name) {
let distribs = feature
.iter()
.map(|(name, version)| Distrib::new(name, *version))
.filter_map(|(name, versions)| {
get_browser_stat(name, opts.mobile_to_desktop)
.map(|(name, stat)| (name, stat, versions))
})
.flat_map(|(name, browser_stat, versions)| {
let desktop_name = opts
.mobile_to_desktop
.then_some(to_desktop_name(name))
.flatten();
let check_desktop = desktop_name.is_some()
&& browser_stat
.version_list
.iter()
.filter(|version| version.release_date.is_some())
.last()
.and_then(|latest_version| versions.get(&*latest_version.version))
.map(|flags| is_supported(*flags))
.unwrap_or_default();
browser_stat
.version_list
.iter()
.filter_map(move |VersionDetail { version, .. }| {
versions
.get(&**version)
.or_else(|| match desktop_name {
Some(desktop_name) if check_desktop => feature
.get(&BrowserNameAtom::from(desktop_name))
.and_then(|versions| versions.get(&**version)),
_ => None,
})
.and_then(|flags| is_supported(*flags).then_some(&*version))
})
.map(move |version| Distrib::new(name, version))
})
.collect();
Ok(distribs)
} else {
Err(Error::UnknownBrowserFeature(name.to_string()))
}
}

fn is_supported(flags: u8) -> bool {
flags & Y != 0 || flags & A != 0
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -25,10 +72,16 @@ mod tests {
#[test_case("supports objectrtc"; "case 1")]
#[test_case("supports rtcpeerconnection"; "case 2")]
#[test_case("supports arrow-functions"; "case 3")]
fn valid(query: &str) {
fn default_options(query: &str) {
run_compare(query, &Opts::new());
}

#[test_case("supports filesystem"; "case 1")]
#[test_case("supports font-smooth"; "case 2")]
fn mobile_to_desktop(query: &str) {
run_compare(query, &Opts::new().mobile_to_desktop(true));
}

#[test]
fn invalid() {
assert_eq!(
Expand Down

0 comments on commit 4233e1f

Please sign in to comment.