1use crate::{
2 data::caniuse,
3 error::Error,
4 opts::Opts,
5 parser::{QueryAtom, Stats, VersionRange},
6 semver::Version,
7};
8use serde::{Deserialize, Serialize};
9use std::{borrow::Cow, fmt::Display};
10
11mod browser_accurate;
12mod browser_bounded_range;
13mod browser_unbounded_range;
14mod browserslist_config;
15mod cover;
16mod cover_by_region;
17mod current_node;
18mod dead;
19mod defaults;
20mod electron_accurate;
21mod electron_bounded_range;
22mod electron_unbounded_range;
23mod extends;
24mod firefox_esr;
25mod last_n_browsers;
26mod last_n_electron;
27mod last_n_electron_major;
28mod last_n_major_browsers;
29mod last_n_node;
30mod last_n_node_major;
31mod last_n_x_browsers;
32mod last_n_x_major_browsers;
33mod maintained_node;
34mod node_accurate;
35mod node_bounded_range;
36mod node_unbounded_range;
37mod op_mini;
38mod percentage;
39mod percentage_by_region;
40mod phantom;
41mod since;
42mod supports;
43mod unreleased_browsers;
44mod unreleased_electron;
45mod unreleased_x_browsers;
46mod years;
47
48#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
49pub struct Distrib(&'static str, Cow<'static, str>);
63
64impl Distrib {
65 #[inline]
66 fn new<S: Into<Cow<'static, str>>>(name: &'static str, version: S) -> Self {
67 Self(name, version.into())
68 }
69
70 #[inline]
71 pub fn name(&self) -> &str {
81 self.0
82 }
83
84 #[inline]
85 pub fn version(&self) -> &str {
95 &self.1
96 }
97}
98
99impl Display for Distrib {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 write!(f, "{} {}", self.0, self.1)
102 }
103}
104
105pub type QueryResult = Result<Vec<Distrib>, Error>;
106
107pub fn query(atom: QueryAtom, opts: &Opts) -> QueryResult {
108 match atom {
109 QueryAtom::Last {
110 count,
111 major,
112 name: Some(name),
113 } if name.eq_ignore_ascii_case("electron") => {
114 let count = count as usize;
115 if major {
116 last_n_electron_major::last_n_electron_major(count)
117 } else {
118 last_n_electron::last_n_electron(count)
119 }
120 }
121 QueryAtom::Last {
122 count,
123 major,
124 name: Some(name),
125 } if name.eq_ignore_ascii_case("node") => {
126 let count = count as usize;
127 if major {
128 last_n_node_major::last_n_node_major(count)
129 } else {
130 last_n_node::last_n_node(count)
131 }
132 }
133 QueryAtom::Last {
134 count,
135 major,
136 name: Some(name),
137 } => {
138 let count = count as usize;
139 if major {
140 last_n_x_major_browsers::last_n_x_major_browsers(count, name, opts)
141 } else {
142 last_n_x_browsers::last_n_x_browsers(count, name, opts)
143 }
144 }
145 QueryAtom::Last {
146 count,
147 major,
148 name: None,
149 } => {
150 let count = count as usize;
151 if major {
152 last_n_major_browsers::last_n_major_browsers(count, opts)
153 } else {
154 last_n_browsers::last_n_browsers(count, opts)
155 }
156 }
157 QueryAtom::Unreleased(Some(name)) if name.eq_ignore_ascii_case("electron") => {
158 unreleased_electron::unreleased_electron()
159 }
160 QueryAtom::Unreleased(Some(name)) => {
161 unreleased_x_browsers::unreleased_x_browsers(name, opts)
162 }
163 QueryAtom::Unreleased(None) => unreleased_browsers::unreleased_browsers(opts),
164 QueryAtom::Years(count) => years::years(count, opts),
165 QueryAtom::Since { year, month, day } => since::since(year, month, day, opts),
166 QueryAtom::Percentage {
167 comparator,
168 popularity,
169 stats: Stats::Global,
170 } => percentage::percentage(comparator, popularity),
171 QueryAtom::Percentage {
172 comparator,
173 popularity,
174 stats: Stats::Region(region),
175 } => percentage_by_region::percentage_by_region(comparator, popularity, region),
176 QueryAtom::Cover {
177 coverage,
178 stats: Stats::Global,
179 } => cover::cover(coverage),
180 QueryAtom::Cover {
181 coverage,
182 stats: Stats::Region(region),
183 } => cover_by_region::cover_by_region(coverage, region),
184 QueryAtom::Supports(name, kind) => supports::supports(name, kind, opts),
185 QueryAtom::Electron(VersionRange::Bounded(from, to)) => {
186 electron_bounded_range::electron_bounded_range(from, to)
187 }
188 QueryAtom::Electron(VersionRange::Unbounded(comparator, version)) => {
189 electron_unbounded_range::electron_unbounded_range(comparator, version)
190 }
191 QueryAtom::Electron(VersionRange::Accurate(version)) => {
192 electron_accurate::electron_accurate(version)
193 }
194 QueryAtom::Node(VersionRange::Bounded(from, to)) => {
195 node_bounded_range::node_bounded_range(from, to)
196 }
197 QueryAtom::Node(VersionRange::Unbounded(comparator, version)) => {
198 node_unbounded_range::node_unbounded_range(comparator, version)
199 }
200 QueryAtom::Node(VersionRange::Accurate(version)) => {
201 node_accurate::node_accurate(version, opts)
202 }
203 QueryAtom::Browser(name, VersionRange::Bounded(from, to)) => {
204 browser_bounded_range::browser_bounded_range(name, from, to, opts)
205 }
206 QueryAtom::Browser(name, VersionRange::Unbounded(comparator, version)) => {
207 browser_unbounded_range::browser_unbounded_range(name, comparator, version, opts)
208 }
209 QueryAtom::Browser(name, VersionRange::Accurate(version)) => {
210 browser_accurate::browser_accurate(name, version, opts)
211 }
212 QueryAtom::FirefoxESR => firefox_esr::firefox_esr(),
213 QueryAtom::OperaMini => op_mini::op_mini(),
214 QueryAtom::CurrentNode => current_node::current_node(),
215 QueryAtom::MaintainedNode => maintained_node::maintained_node(),
216 QueryAtom::Phantom(is_later_version) => phantom::phantom(is_later_version),
217 QueryAtom::BrowserslistConfig => browserslist_config::browserslist_config(opts),
218 QueryAtom::Defaults => defaults::defaults(opts),
219 QueryAtom::Dead => dead::dead(opts),
220 QueryAtom::Extends(pkg) => extends::extends(pkg, opts),
221 QueryAtom::Unknown(query) => Err(Error::UnknownQuery(query.into())),
222 }
223}
224
225pub fn count_filter_versions(name: &str, mobile_to_desktop: bool, count: usize) -> usize {
226 let jump = match name {
227 "android" => {
228 if mobile_to_desktop {
229 return count;
230 } else {
231 let last_released = &caniuse::get_browser_stat("android", mobile_to_desktop)
232 .unwrap()
233 .1
234 .version_list
235 .iter()
236 .filter(|version| version.release_date.is_some())
237 .map(|version| version.version)
238 .last()
239 .unwrap()
240 .parse::<f32>()
241 .unwrap();
242 (last_released - caniuse::ANDROID_EVERGREEN_FIRST) as usize
243 }
244 }
245 "op_mob" => {
246 let lastest = caniuse::get_browser_stat("android", mobile_to_desktop)
247 .unwrap()
248 .1
249 .version_list
250 .last()
251 .unwrap();
252 (lastest.version.parse::<Version>().unwrap().major() - caniuse::OP_MOB_BLINK_FIRST + 1)
253 as usize
254 }
255 _ => return count,
256 };
257 if count <= jump {
258 1
259 } else {
260 count + 1 - jump
261 }
262}