1use anyhow::Error;
7use serde::{Deserialize, Serialize};
8use st_map::StaticMap;
9
10use self::version::Version;
11
12pub mod query;
13pub mod version;
14
15#[derive(Debug, Default, Deserialize, Clone, Copy, Serialize, StaticMap, PartialEq, Eq)]
17#[serde(deny_unknown_fields)]
18pub struct BrowserData<T: Default> {
19 #[serde(default)]
20 pub chrome: T,
21 #[serde(default, rename = "chrome-android")]
22 pub chrome_android: T,
23 #[serde(default, rename = "firefox-android")]
24 pub firerfox_android: T,
25 #[serde(default, rename = "opera-android")]
26 pub opera_android: T,
27
28 #[serde(default)]
29 pub quest: T,
30 #[serde(default, rename = "react-native")]
31 pub react_native: T,
32
33 #[serde(default)]
34 pub and_chr: T,
35 #[serde(default)]
36 pub and_ff: T,
37 #[serde(default)]
38 pub op_mob: T,
39 #[serde(default)]
40 pub ie: T,
41 #[serde(default)]
42 pub edge: T,
43 #[serde(default)]
44 pub firefox: T,
45 #[serde(default)]
46 pub safari: T,
47 #[serde(default)]
48 pub node: T,
49 #[serde(default)]
50 pub ios: T,
51 #[serde(default)]
52 pub samsung: T,
53 #[serde(default)]
54 pub opera: T,
55 #[serde(default)]
56 pub android: T,
57 #[serde(default)]
58 pub electron: T,
59 #[serde(default)]
60 pub phantom: T,
61 #[serde(default)]
62 pub opera_mobile: T,
63 #[serde(default)]
64 pub rhino: T,
65 #[serde(default)]
66 pub deno: T,
67 #[serde(default)]
68 pub hermes: T,
69 #[serde(default)]
70 pub oculus: T,
71 #[serde(default)]
72 pub bun: T,
73}
74
75impl<T> BrowserData<T>
76where
77 T: Default,
78{
79 pub fn insert(&mut self, k: &str, v: T) -> T {
80 for (key, value) in self.iter_mut() {
81 if k == key {
82 return std::mem::replace(value, v);
83 }
84 }
85
86 panic!("unknown key: {}", k)
87 }
88}
89
90pub type Versions = BrowserData<Option<Version>>;
95
96impl BrowserData<Option<Version>> {
97 pub fn is_any_target(&self) -> bool {
99 self.iter().all(|(_, v)| v.is_none())
100 }
101
102 pub fn parse_versions(distribs: Vec<browserslist::Distrib>) -> Result<Self, Error> {
104 fn remap(key: &str) -> &str {
105 match key {
106 "and_chr" => "chrome",
107 "and_ff" => "firefox",
108 "ie_mob" => "ie",
109 "ios_saf" => "ios",
110 "op_mob" => "opera",
111 _ => key,
112 }
113 }
114
115 let mut data: Versions = BrowserData::default();
116 for dist in distribs {
117 let browser = dist.name();
118 let browser = remap(browser);
119 let version = dist.version();
120 match browser {
121 "and_qq" | "and_uc" | "baidu" | "bb" | "kaios" | "op_mini" => continue,
122
123 _ => {}
124 }
125
126 let version = version
127 .split_once('-')
128 .map(|(version, _)| version)
129 .unwrap_or(version)
130 .parse()
131 .ok();
132
133 let version = match version {
134 Some(v) => v,
135 None => continue,
136 };
137
138 if data[&browser].map(|v| v > version).unwrap_or(true) {
140 for (k, v) in data.iter_mut() {
141 if browser == k {
142 *v = Some(version);
143 }
144 }
145 }
146 }
147
148 Ok(data)
149 }
150}