browserslist/queries/
supports.rs1use super::{Distrib, QueryResult};
2use crate::{error::Error, parser::SupportKind, Opts};
3use browserslist_data::caniuse::{features::get_feature_stat, get_browser_stat, to_desktop_name};
4
5const Y: u8 = 1;
6const A: u8 = 2;
7
8pub(super) fn supports(name: &str, kind: Option<SupportKind>, opts: &Opts) -> QueryResult {
9 let include_partial = matches!(kind, Some(SupportKind::Partially) | None);
10
11 if let Some(feature) = get_feature_stat(name) {
12 let distribs = feature
13 .iter()
14 .filter_map(|(name, versions)| {
15 get_browser_stat(name, opts.mobile_to_desktop)
16 .map(|(name, stat)| (name, stat, versions))
17 })
18 .flat_map(|(name, browser_stat, versions)| {
19 let desktop_name = opts
20 .mobile_to_desktop
21 .then_some(to_desktop_name(name))
22 .flatten();
23 let check_desktop = desktop_name.is_some()
24 && browser_stat
25 .iter()
26 .filter(|version| version.released)
27 .filter_map(|latest_version| versions.get(latest_version.version()))
28 .next_back()
29 .is_some_and(|flags| is_supported(flags, include_partial));
30 browser_stat
31 .iter()
32 .filter_map(move |version| {
33 versions
34 .get(version.version())
35 .or_else(|| match desktop_name {
36 Some(desktop_name) if check_desktop => feature
37 .get(desktop_name)
38 .and_then(|versions| versions.get(version.version())),
39 _ => None,
40 })
41 .and_then(|flags| {
42 is_supported(flags, include_partial).then_some(version)
43 })
44 })
45 .map(move |version| Distrib::new(name, version.version()))
46 })
47 .collect();
48 Ok(distribs)
49 } else {
50 Err(Error::UnknownBrowserFeature(name.to_string()))
51 }
52}
53
54fn is_supported(flags: u8, include_partial: bool) -> bool {
55 flags & Y != 0 || include_partial && flags & A != 0
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use crate::{
62 opts::Opts,
63 test::{run_compare, should_failed},
64 };
65 use test_case::test_case;
66
67 #[test_case("supports objectrtc"; "case 1")]
68 #[test_case("supports rtcpeerconnection"; "case 2")]
69 #[test_case("supports arrow-functions"; "case 3")]
70 #[test_case("partially supports rtcpeerconnection"; "partially")]
71 #[test_case("fully supports rtcpeerconnection"; "fully")]
72 fn default_options(query: &str) {
73 run_compare(query, &Opts::default(), None);
74 }
75
76 #[test_case("supports filesystem"; "case 1")]
77 #[test_case("supports font-smooth"; "case 2")]
78 fn mobile_to_desktop(query: &str) {
79 run_compare(
80 query,
81 &Opts {
82 mobile_to_desktop: true,
83 ..Default::default()
84 },
85 None,
86 );
87 }
88
89 #[test]
90 fn invalid() {
91 assert_eq!(
92 should_failed("supports xxxyyyzzz", &Opts::default()),
93 Error::UnknownBrowserFeature(String::from("xxxyyyzzz"))
94 );
95 }
96}