mod accordion;
mod add_to_cart;
mod disclosure_menu;
pub(crate) mod easy_language;
mod form;
pub mod help_mechanisms;
mod main_navigation;
mod modal_dialog;
mod quantity_stepper;
pub(crate) mod skip_link;
mod tab_list;
pub(crate) use disclosure_menu::NATIVE_DISCLOSURE_ROLES;
use serde::{Deserialize, Serialize};
use crate::accessibility::AXTree;
use crate::wcag::types::Violation;
pub(crate) const PURCHASE_FINAL_HINTS: &[&str] = &[
"zahlungspflichtig bestellen",
"jetzt kaufen",
"kaufen",
"bestellen",
"buy now",
"place order",
"complete purchase",
"complete order",
"pay",
"checkout",
"buchen",
"book now",
"reservieren",
"reserve",
];
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PatternAnalysis {
pub recognized: Vec<RecognizedPattern>,
pub violations: Vec<Violation>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub journey_candidates: Vec<JourneyCandidate>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub help_mechanisms: Vec<help_mechanisms::HelpMechanism>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JourneyCandidate {
pub pattern_kind: PatternKind,
pub trigger_backend_id: Option<i64>,
pub controlled_backend_id: Option<i64>,
pub confidence: f32,
pub required_journey: JourneyKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PatternKind {
Modal,
Disclosure,
Tabs,
Menu,
Accordion,
Form,
SkipLink,
AddToCart,
QuantityStepper,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum JourneyKind {
ModalOpen,
DisclosureToggle,
TabsNavigate,
MenuOpen,
AccordionToggle,
FormErrorSubmit,
SkipLinkActivate,
AddToCart,
QuantityStepper,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RecognizedPattern {
pub pattern: String,
pub message: String,
pub confidence: PatternConfidence,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum PatternConfidence {
Strong,
Partial,
}
impl PatternAnalysis {
pub fn add_recognized(
&mut self,
pattern: &str,
message: impl Into<String>,
confidence: PatternConfidence,
) {
self.recognized.push(RecognizedPattern {
pattern: pattern.to_string(),
message: message.into(),
confidence,
});
}
pub fn has_recognized(&self, pattern: &str) -> bool {
self.recognized.iter().any(|r| r.pattern == pattern)
}
}
pub fn analyze(tree: &AXTree) -> PatternAnalysis {
let mut result = PatternAnalysis::default();
main_navigation::detect(tree, &mut result);
disclosure_menu::detect(tree, &mut result);
modal_dialog::detect(tree, &mut result);
tab_list::detect(tree, &mut result);
skip_link::detect(tree, &mut result);
accordion::detect(tree, &mut result);
form::detect(tree, &mut result);
add_to_cart::detect(tree, &mut result);
quantity_stepper::detect(tree, &mut result);
result
}