browserslist/queries/
supports.rs

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
101
102
103
use super::{Distrib, QueryResult};
use crate::{
    data::caniuse::{features::get_feature_stat, get_browser_stat, to_desktop_name, VersionDetail},
    error::Error,
    parser::SupportKind,
    Opts,
};

const Y: u8 = 1;
const A: u8 = 2;

pub(super) fn supports(name: &str, kind: Option<SupportKind>, opts: &Opts) -> QueryResult {
    let include_partial = matches!(kind, Some(SupportKind::Partially) | None);

    if let Some(feature) = get_feature_stat(name) {
        let distribs = feature
            .iter()
            .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, include_partial))
                        .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(desktop_name)
                                    .and_then(|versions| versions.get(version)),
                                _ => None,
                            })
                            .and_then(|flags| {
                                is_supported(*flags, include_partial).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, include_partial: bool) -> bool {
    flags & Y != 0 || include_partial && flags & A != 0
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        opts::Opts,
        test::{run_compare, should_failed},
    };
    use test_case::test_case;

    #[test_case("supports objectrtc"; "case 1")]
    #[test_case("supports    rtcpeerconnection"; "case 2")]
    #[test_case("supports        arrow-functions"; "case 3")]
    #[test_case("partially supports rtcpeerconnection"; "partially")]
    #[test_case("fully     supports rtcpeerconnection"; "fully")]
    fn default_options(query: &str) {
        run_compare(query, &Opts::default(), None);
    }

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

    #[test]
    fn invalid() {
        assert_eq!(
            should_failed("supports xxxyyyzzz", &Opts::default()),
            Error::UnknownBrowserFeature(String::from("xxxyyyzzz"))
        );
    }
}