use serde_json::Value;
use crate::ai_transparency::AiTransparencyAnalysis;
use crate::ai_visibility::AiVisibilityAnalysis;
use crate::audit::{AuditReport, PerformanceResults};
use crate::best_practices::BestPracticesAnalysis;
use crate::commerce::CommerceAnalysis;
use crate::content_visibility::ContentVisibilityAnalysis;
use crate::dark_mode::DarkModeAnalysis;
use crate::design_quality::DesignQualityAnalysis;
use crate::html_conform::HtmlConformAnalysis;
#[cfg(feature = "pdf")]
use crate::i18n::I18n;
use crate::journey::JourneyAnalysis;
use crate::mobile::MobileFriendliness;
use crate::network::dns::NetworkDnsAnalysis;
use crate::patterns::PatternAnalysis;
use crate::security::SecurityAnalysis;
use crate::seo::SeoAnalysis;
use crate::source_quality::SourceQualityAnalysis;
use crate::tech_stack::TechStackAnalysis;
use crate::ux::UxAnalysis;
#[cfg(feature = "pdf")]
pub type PdfComponents = Vec<Box<dyn renderreport::components::Component>>;
pub trait ReportModule {
fn module_key(&self) -> &'static str;
fn to_json(&self) -> Value;
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents;
}
#[cfg(feature = "pdf")]
fn pdf_marker(module_key: &str, i18n: &I18n) -> PdfComponents {
vec![Box::new(renderreport::components::text::TextBlock::new(
format!("pdf-module:{module_key}:{}", i18n.locale()),
))]
}
pub const REPORT_AREAS: &[&str] = &[
"wcag_findings",
"a11y_journey",
"audit_flags",
"search_experience",
"screen_reader",
"advisory_findings",
"score_breakdown",
];
impl ReportModule for PerformanceResults {
fn module_key(&self) -> &'static str {
"performance"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for SeoAnalysis {
fn module_key(&self) -> &'static str {
"seo"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for SecurityAnalysis {
fn module_key(&self) -> &'static str {
"security"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for HtmlConformAnalysis {
fn module_key(&self) -> &'static str {
"html_conform"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for MobileFriendliness {
fn module_key(&self) -> &'static str {
"mobile"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for UxAnalysis {
fn module_key(&self) -> &'static str {
"ux"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for JourneyAnalysis {
fn module_key(&self) -> &'static str {
"journey"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for DarkModeAnalysis {
fn module_key(&self) -> &'static str {
"dark_mode"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for DesignQualityAnalysis {
fn module_key(&self) -> &'static str {
"design_quality"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for AiTransparencyAnalysis {
fn module_key(&self) -> &'static str {
"ai_transparency"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for NetworkDnsAnalysis {
fn module_key(&self) -> &'static str {
"network_dns"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for SourceQualityAnalysis {
fn module_key(&self) -> &'static str {
"source_quality"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for AiVisibilityAnalysis {
fn module_key(&self) -> &'static str {
"ai_visibility"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for ContentVisibilityAnalysis {
fn module_key(&self) -> &'static str {
"content_visibility"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for BestPracticesAnalysis {
fn module_key(&self) -> &'static str {
"best_practices"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for CommerceAnalysis {
fn module_key(&self) -> &'static str {
"commerce"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for TechStackAnalysis {
fn module_key(&self) -> &'static str {
"tech_stack"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
impl ReportModule for PatternAnalysis {
fn module_key(&self) -> &'static str {
"patterns"
}
fn to_json(&self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
#[cfg(feature = "pdf")]
fn render_pdf(&self, i18n: &I18n) -> PdfComponents {
pdf_marker(self.module_key(), i18n)
}
}
pub fn active_modules(report: &AuditReport) -> Vec<(&'static str, Value)> {
let mut out: Vec<(&'static str, Value)> = Vec::new();
let mut push = |m: &dyn ReportModule| out.push((m.module_key(), m.to_json()));
if let Some(ref m) = report.performance {
push(m);
}
if let Some(ref m) = report.discoverability.seo {
push(m);
}
if let Some(ref m) = report.security {
push(m);
}
if let Some(ref m) = report.html_conform {
push(m);
}
if let Some(ref m) = report.experience.mobile {
push(m);
}
if let Some(ref m) = report.ux {
push(m);
}
if let Some(ref m) = report.journey {
push(m);
}
if let Some(ref m) = report.experience.dark_mode {
push(m);
}
if let Some(ref m) = report.experience.design_quality {
push(m);
}
if let Some(ref m) = report.experience.ai_transparency {
push(m);
}
if let Some(ref m) = report.experience.network_dns {
push(m);
}
if let Some(ref m) = report.discoverability.source_quality {
push(m);
}
if let Some(ref m) = report.discoverability.ai_visibility {
push(m);
}
if let Some(ref m) = report.discoverability.content_visibility {
push(m);
}
if let Some(ref m) = report.best_practices {
push(m);
}
if let Some(ref m) = report.commerce {
push(m);
}
if let Some(ref m) = report.discoverability.tech_stack {
push(m);
}
if let Some(ref m) = report.patterns {
push(m);
}
out
}
#[cfg(feature = "pdf")]
pub fn active_report_modules(report: &AuditReport) -> Vec<&dyn ReportModule> {
let mut out: Vec<&dyn ReportModule> = Vec::new();
macro_rules! push_module {
($field:expr) => {
if let Some(ref m) = $field {
out.push(m);
}
};
}
push_module!(report.performance);
push_module!(report.discoverability.seo);
push_module!(report.security);
push_module!(report.html_conform);
push_module!(report.experience.mobile);
push_module!(report.ux);
push_module!(report.journey);
push_module!(report.experience.dark_mode);
push_module!(report.experience.design_quality);
push_module!(report.experience.ai_transparency);
push_module!(report.experience.network_dns);
push_module!(report.discoverability.source_quality);
push_module!(report.discoverability.ai_visibility);
push_module!(report.discoverability.content_visibility);
push_module!(report.best_practices);
push_module!(report.commerce);
push_module!(report.discoverability.tech_stack);
push_module!(report.patterns);
out
}