1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use serde::{Deserialize, Serialize};
#[derive(Serialize, Debug, Deserialize, Clone, Copy, Default)]
#[allow(missing_docs)]
pub struct Browsers {
pub android: Option<u32>,
pub chrome: Option<u32>,
pub edge: Option<u32>,
pub firefox: Option<u32>,
pub ie: Option<u32>,
pub ios_saf: Option<u32>,
pub opera: Option<u32>,
pub safari: Option<u32>,
pub samsung: Option<u32>,
}
#[cfg(feature = "browserslist")]
impl Browsers {
pub fn from_browserslist<S: AsRef<str>, I: IntoIterator<Item = S>>(
query: I,
) -> Result<Option<Browsers>, browserslist::Error> {
use browserslist::{resolve, Opts};
let res = resolve(query, &Opts::new())?;
let mut browsers = Browsers::default();
let mut has_any = false;
for distrib in res {
macro_rules! browser {
($browser: ident) => {{
if let Some(v) = parse_version(distrib.version()) {
if browsers.$browser.is_none() || v < browsers.$browser.unwrap() {
browsers.$browser = Some(v);
has_any = true;
}
}
}};
}
match distrib.name() {
"android" => browser!(android),
"chrome" | "and_chr" => browser!(chrome),
"edge" => browser!(edge),
"firefox" | "and_ff" => browser!(firefox),
"ie" => browser!(ie),
"ios_saf" => browser!(ios_saf),
"opera" | "op_mob" => browser!(opera),
"safari" => browser!(safari),
"samsung" => browser!(samsung),
_ => {}
}
}
if !has_any {
return Ok(None);
}
Ok(Some(browsers))
}
}
#[cfg(feature = "browserslist")]
fn parse_version(version: &str) -> Option<u32> {
let version = version.split('-').next();
if version.is_none() {
return None;
}
let mut version = version.unwrap().split('.');
let major = version.next().and_then(|v| v.parse::<u32>().ok());
if let Some(major) = major {
let minor = version.next().and_then(|v| v.parse::<u32>().ok()).unwrap_or(0);
let patch = version.next().and_then(|v| v.parse::<u32>().ok()).unwrap_or(0);
let v: u32 = (major & 0xff) << 16 | (minor & 0xff) << 8 | (patch & 0xff);
return Some(v);
}
None
}