pochoir-extra 0.12.2

Extra utilities for the pochoir template engine
Documentation
//! Accessibility checker used to display accessibility reports in debug mode using [axe-core](https://github.com/dequelabs/axe-core).

#[cfg(debug_assertions)]
use pochoir::{
    parser::{Attrs, Node, TreeRefId},
    template_engine::TemplateBlock,
    Spanned, TransformerResult, TransformerTreeContext,
};
#[cfg(debug_assertions)]
use std::borrow::Cow;

use pochoir::transformers::Transformer;

#[cfg(debug_assertions)]
const CHECKER_JS: &str = concat!(
    include_str!("axe.min.js"),
    r#"document.addEventListener("DOMContentLoaded", () => {
  axe
    .run()
    .then(results => {
    if (results.violations.length) {
      console.warn(`${results.violations.length} accessibility issues found:`);
      console.table(results.violations);
    } else {
      console.info("No accessibility issues found!");
    }
  })
    .catch(err => {
    console.error(`Something bad happened when checking accessibility: ${err.message}`);
  });
});"#
);

/// Add the accessibility checker to the current template (only in debug mode).
///
/// This structure holds a counter to make sure it is only added once per-template and not
/// per-component.
///
/// # Example
///
/// ```no_run
/// use pochoir::{lang::Context, ComponentFile, transformers::Transformers};
/// use pochoir_extra::AccessibilityChecker;
///
/// let source = r#"<img src="https://pa1.narvii.com/6543/1cc43a342a90136e3c7da42fa7fac557b4c41738_00.gif">"#;
/// let file_path = std::path::Path::new("index.html");
/// let mut transformers = Transformers::new()
///     .with_transformer(AccessibilityChecker::new());
///
/// pochoir::transform_and_compile("index", &mut Context::new(), |name| {
///     Ok(ComponentFile::new(file_path, source))
/// }, &mut transformers);
/// ```
///
/// If you check the console (only in debug mode) you'll find a table containing a line with `image-alt` as ID.
#[derive(Debug)]
pub struct AccessibilityChecker;

impl AccessibilityChecker {
    /// Create a new [`AccessibilityChecker`].
    pub fn new() -> Self {
        Self
    }
}

impl Transformer for AccessibilityChecker {
    #[cfg(debug_assertions)]
    fn on_tree_parsed(&mut self, ctx: &mut TransformerTreeContext) -> TransformerResult {
        // Add <script> node as a child of <body> if possible or as the last child
        let parent = ctx.tree.select("body").unwrap().unwrap_or(TreeRefId::Root);
        let script_id = ctx.tree.insert(
            parent,
            Spanned::new(Node::Element(Cow::Borrowed("script"), Attrs::new())),
        );
        let _text_id = ctx.tree.insert(
            script_id,
            Spanned::new(Node::TemplateBlock(TemplateBlock::RawText(Cow::Borrowed(
                CHECKER_JS,
            )))),
        );

        Ok(())
    }
}

impl Default for AccessibilityChecker {
    fn default() -> Self {
        Self::new()
    }
}