accessibility_rs/engine/audit/
wcag.rs

1use crate::engine::issue::Issue;
2use crate::engine::rules::rule::RuleValidation;
3use crate::engine::rules::wcag_rule_map::RULES_A;
4use crate::Auditor;
5#[cfg(feature = "rayon")]
6use rayon::prelude::*;
7
8#[derive(Default)]
9/// Baseline for all rules
10pub struct WCAGAAA;
11
12/// WCAG rules to test for
13impl WCAGAAA {
14    /// Audit html against WCAGAAA standards
15    #[cfg(not(feature = "tokio"))]
16    pub fn run_audit(auditor: (Auditor<'_>, Option<taffy::TaffyTree>)) -> Vec<Issue> {
17        use crate::engine::audit::audit_utils::push_issue_base;
18        let mut issues: Vec<Issue> = Vec::new();
19
20        for node in auditor.0.tree.iter() {
21            match RULES_A.get(&*node.0) {
22                Some(rules) => {
23                    for rule in rules {
24                        match (rule.validate)(&node.1, &auditor.0) {
25                            RuleValidation::Single(validation) => push_issue_base(
26                                validation,
27                                rule,
28                                &node.0,
29                                &auditor.0.locale,
30                                &mut issues,
31                            ),
32                            RuleValidation::Multi(validation) => {
33                                for v in validation {
34                                    push_issue_base(
35                                        v,
36                                        rule,
37                                        &node.0,
38                                        &auditor.0.locale,
39                                        &mut issues,
40                                    )
41                                }
42                            }
43                        };
44                    }
45                }
46                _ => (),
47            }
48        }
49
50        issues
51    }
52
53    /// Audit html against WCAGAAA standards
54    #[cfg(feature = "tokio")]
55    pub async fn run_audit(auditor: (Auditor<'_>, Option<taffy::TaffyTree>)) -> Vec<Issue> {
56        use crate::engine::audit::audit_utils::push_issue_base;
57        use tokio_stream::{self as stream, StreamExt};
58        let mut issues: Vec<Issue> = Vec::new();
59        let stream = stream::iter(auditor.0.tree.iter());
60        tokio::pin!(stream);
61
62        while let Some(node) = stream.next().await {
63            match RULES_A.get(&*node.0) {
64                Some(rules) => {
65                    for rule in rules {
66                        match (rule.validate)(&node.1, &auditor.0) {
67                            RuleValidation::Single(validation) => push_issue_base(
68                                validation,
69                                rule,
70                                &node.0,
71                                &auditor.0.locale,
72                                &mut issues,
73                            ),
74                            RuleValidation::Multi(validation) => {
75                                for v in validation {
76                                    push_issue_base(
77                                        v,
78                                        rule,
79                                        &node.0,
80                                        &auditor.0.locale,
81                                        &mut issues,
82                                    )
83                                }
84                            }
85                        };
86                    }
87                }
88                _ => (),
89            }
90        }
91
92        issues
93    }
94
95    /// Audit html against WCAGAAA standards
96    #[cfg(all(feature = "rayon", not(feature = "spider"), not(feature = "tokio")))]
97    pub fn audit(auditor: (Auditor<'_>, Option<taffy::TaffyTree>)) -> Vec<Issue> {
98        use crate::engine::audit::audit_utils::evaluate_rules_in_parallel;
99
100        if auditor.0.document.tree.nodes().len() <= 5500 {
101            WCAGAAA::run_audit(auditor)
102        } else {
103            let (s, r) = crossbeam_channel::unbounded();
104
105            auditor.0.tree.par_iter().for_each(|node| {
106                if let Some(rules) = RULES_A.get(&*node.0) {
107                    evaluate_rules_in_parallel(rules, &node, &auditor.0, &s);
108                }
109            });
110
111            drop(s);
112
113            r.iter().collect()
114        }
115    }
116
117    /// Audit html against WCAGAAA standards
118    #[cfg(all(
119        not(feature = "rayon"),
120        not(feature = "spider"),
121        not(feature = "tokio")
122    ))]
123    pub fn audit(auditor: (Auditor<'_>, Option<taffy::TaffyTree>)) -> Vec<Issue> {
124        WCAGAAA::run_audit(auditor)
125    }
126
127    /// Audit html against WCAGAAA standards
128    #[cfg(feature = "tokio")]
129    pub async fn audit(auditor: (Auditor<'_>, Option<taffy::TaffyTree>)) -> Vec<Issue> {
130        WCAGAAA::run_audit(auditor).await
131    }
132}