From ac5f76580e5922aca5595692294d26186db46468 Mon Sep 17 00:00:00 2001 From: j-mendez Date: Fri, 29 Sep 2023 10:18:19 -0400 Subject: [PATCH] chore(innate): add accessibility tree building --- README.md | 6 +- kayle/lib/wasm/css.ts | 20 + kayle/lib/wasm/extract.ts | 5 +- kayle/lib/wasm/index.ts | 1 + kayle_innate/Cargo.toml | 2 +- kayle_innate/README.md | 6 + kayle_innate/src/engine/rules.rs | 1 + kayle_innate/src/i18n/locales.rs | 1 + kayle_innate/src/lib.rs | 68 +-- kayle_innate/tests/mock.rs | 957 +++++++++++++++++++++++++++++++ kayle_innate/tests/web.rs | 52 +- package.json | 3 +- 12 files changed, 1041 insertions(+), 81 deletions(-) create mode 100644 kayle/lib/wasm/css.ts create mode 100644 kayle_innate/src/engine/rules.rs create mode 100644 kayle_innate/src/i18n/locales.rs create mode 100644 kayle_innate/tests/mock.rs diff --git a/README.md b/README.md index 0bad665d..a7f655e0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ✨ kayle -The futuristic web accessibility engine. +The blazing fast and accurate web accessibility engine. ## Getting Started @@ -218,6 +218,10 @@ Run the following to install on ^node@18 Use the command `yarn build` to compile all the scripts for each locale. +## Rust Runner + +We are building a rust based runner called [kayle_innate](./kayle_innate/) that can port to wasm that will take the audits into the nanoseconds - low milliseconds zone. + ## Discord If you want to chat about the project checkout our [Discord](https://discord.gg/ukmJcjQ5). diff --git a/kayle/lib/wasm/css.ts b/kayle/lib/wasm/css.ts new file mode 100644 index 00000000..a2c67eb2 --- /dev/null +++ b/kayle/lib/wasm/css.ts @@ -0,0 +1,20 @@ +import type { RunnerConfig } from "../config"; + +// get all the css of the document to send to rust +export const getAllCss = async (config: RunnerConfig) => { + return await config.page.evaluate(() => { + return [...document.styleSheets] + .map((styleSheet) => { + try { + return [...styleSheet.cssRules].map((rule) => rule.cssText).join(""); + } catch (e) { + console.log( + "Access to stylesheet %s is denied.", + styleSheet.href + ); + } + }) + .filter(Boolean) + .join("\n"); + }); +}; diff --git a/kayle/lib/wasm/extract.ts b/kayle/lib/wasm/extract.ts index b3c9a1cc..3967ba84 100644 --- a/kayle/lib/wasm/extract.ts +++ b/kayle/lib/wasm/extract.ts @@ -10,5 +10,8 @@ import type { RunnerConfig } from "../config"; export async function extractLinks(config: RunnerConfig, target?: string) { const htmlContent = await config.page.content(); const domain = typeof target === "string" ? target : config.page.url(); - return get_document_links(htmlContent, domain !== "about:blank" ? domain : ""); + return get_document_links( + htmlContent, + domain !== "about:blank" ? domain : "" + ); } diff --git a/kayle/lib/wasm/index.ts b/kayle/lib/wasm/index.ts index 7b8d2f99..03f1a88b 100644 --- a/kayle/lib/wasm/index.ts +++ b/kayle/lib/wasm/index.ts @@ -1 +1,2 @@ export { extractLinks } from "./extract"; +export { getAllCss } from "./css" \ No newline at end of file diff --git a/kayle_innate/Cargo.toml b/kayle_innate/Cargo.toml index 0800114e..ac36bb6a 100644 --- a/kayle_innate/Cargo.toml +++ b/kayle_innate/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/a11ywatch/kayle" crate-type = ["cdylib", "rlib"] [features] -default = ["console_error_panic_hook"] +default = ["console_error_panic_hook", "accessibility"] accessibility = ["select"] [dependencies] diff --git a/kayle_innate/README.md b/kayle_innate/README.md index 122dae0d..f3b00072 100644 --- a/kayle_innate/README.md +++ b/kayle_innate/README.md @@ -31,3 +31,9 @@ In order to test the accessibility parser in Rust run. 1. Port expensive functions to wasm with preloading capabilities injection into browsers. 1. Reborn the accessibility testing in rust. + +## Notes + +For creating a rust based wasm accessibility runner we have a high surface level of getting 35ms audits [medium](./tests/mock.rs) case +from the fastesdt audits `fast_htmlcs` 200-300ms on a large run. This leads us to the possibility of porting this over +to get the drastic benefits from a re-write. diff --git a/kayle_innate/src/engine/rules.rs b/kayle_innate/src/engine/rules.rs new file mode 100644 index 00000000..ff11b5ae --- /dev/null +++ b/kayle_innate/src/engine/rules.rs @@ -0,0 +1 @@ +// accessibility rules todo: diff --git a/kayle_innate/src/i18n/locales.rs b/kayle_innate/src/i18n/locales.rs new file mode 100644 index 00000000..7a96e95f --- /dev/null +++ b/kayle_innate/src/i18n/locales.rs @@ -0,0 +1 @@ +// support for based locales in readme diff --git a/kayle_innate/src/lib.rs b/kayle_innate/src/lib.rs index d5875dfd..0b4e27b6 100644 --- a/kayle_innate/src/lib.rs +++ b/kayle_innate/src/lib.rs @@ -4,7 +4,7 @@ extern crate lazy_static; mod utils; use case_insensitive_string::CaseInsensitiveString; use std::collections::HashSet; -use utils::{convert_abs_path, convert_base_path, set_panic_hook, domain_name}; +use utils::{convert_abs_path, convert_base_path, domain_name, set_panic_hook}; use wasm_bindgen::prelude::*; #[cfg(feature = "wee_alloc")] @@ -124,12 +124,14 @@ pub fn get_document_links(res: &str, domain: &str) -> Box<[JsValue]> { links.into_boxed_slice() } -#[wasm_bindgen] // RUST_LOG=info wasm-pack test --firefox --headless --features accessibility --release #[cfg(feature = "accessibility")] /// try to fix all possible issues using a spec against the tree. -pub fn parse_accessibility_tree(html: &str) { +pub fn parse_accessibility_tree( + html: &str, +) -> std::collections::BTreeMap> { set_panic_hook(); + use std::collections::BTreeMap; #[wasm_bindgen] extern "C" { @@ -158,60 +160,58 @@ pub fn parse_accessibility_tree(html: &str) { // The chrome browser we can set to ignore all assets and fetch them here but, it would be re-doing the wheel. // If we can send the Stylesheets from node to rust this could leverage the sheets attached since we just need the node references. - let mut n = 0; let t = now(); + let mut n = 0; + let mut accessibility_tree: BTreeMap, Vec<_>> = BTreeMap::new(); + let d = select::document::Document::from(html); - // measure select parsing doc 1:1 around 34ms - gets slower when using methods possibly due to clones - while let Some(node) = select::document::Document::from(html).nth(n) { + // measure select parsing doc 1:1 around 25ms + while let Some(node) = d.nth(n) { let element_name = node.name(); - console_log!("{:?}", element_name); + // console_log!("{:?}", element_name); + accessibility_tree + .entry(element_name) + .and_modify(|n| n.push(node)) + .or_insert(Vec::from([node])); n += 1; } + console_log!("Select Parser duration {:?}ms", now() - t); + // console_log!("Tree {:?}", accessibility_tree); let t = now(); - // parse doc will start from html downwards let h = scraper::Html::parse_document(html); + // accessibility tree for ordered element mappings + let mut accessibility_tree: BTreeMap> = BTreeMap::new(); let mut hh = h.tree.nodes(); // measure select parsing doc 1:1 around 10ms while let Some(node) = hh.next() { if let Some(element) = node.value().as_element() { let element_name = element.name(); - console_log!("{:?}", element_name); + // console_log!("{:?}", element_name); + accessibility_tree + .entry(element_name.to_string()) + .and_modify(|n| n.push(element.to_owned())) + .or_insert(Vec::from([element.to_owned()])); } } - // "html" - // "head" - // "title" - // "meta" - // "link" - // "style" - // "body" - // "header" - // "nav" - // "a" - // "a" - // "main" - // "h1" - // "p" - // "input" - // "footer" - // "ul" - // "li" console_log!("Scraper Parser: duration {:?}ms", now() - t); + console_log!("Getting tree links {:?}", accessibility_tree.get("a")); + + accessibility_tree + // console_log!("Tree {:?}", accessibility_tree); } #[wasm_bindgen] -/// use gpu to accelerate layout rendering or workers. -pub fn validate_node() { - todo!("It will validate a node whether accessibility checks should arise.") +/// audit a web page passing the html and css rules. +pub fn audit(html: &str, _css_rules: &str) { + let _tree = parse_accessibility_tree(&html); } -#[wasm_bindgen] -/// Perform the a judgement against a page to determine effort, access, and more. -pub fn judge() { - todo!("Determine the score of the website after the tree was built.") +/// parse css tree to maps +pub fn parse_css(_css: &str) { + // parse the css to a list of nodes capable of o1 getting results } diff --git a/kayle_innate/tests/mock.rs b/kayle_innate/tests/mock.rs new file mode 100644 index 00000000..e5ef3a95 --- /dev/null +++ b/kayle_innate/tests/mock.rs @@ -0,0 +1,957 @@ +/// mock website data from drake.com +pub static MOCK_WEBSITE_HTML: &'static str = r###" + + + + + + + Drake Industries | Custom, Durable, High-Quality Labels, Asset Tags and Custom Server Bezels + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+ +
+
+
+ +
+
+
+
Request a Quote
+ +
+
+
+ + + +
+
+
+ +
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ Main_BG_sm
+
+
+
+ +
+
+
+ +
+
+
+
+

SAME DAY QUOTES
INDUSTRY LEADING PRODUCT IDENTIFICATION

+
+
+
+ +
+
+
+
+
+ Drake has earned the trust of private industries, US, state & local governments and NASA.
+
+
+
+
+ +
+
+
+
+ REQUEST QUOTE
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ + + +

+ + + + + + + + Welcome to Drake Industries

+ +
+
+
+ +
+
+
+
+ Product_Group_Img
+
+
+ +
+
+
+
Drake Industries is a manufacturer of high-quality, durable labels, nameplates, and ID tags for companies ranging from local restaurants… to PC builders… to NASA. Drake understands that you choose label solutions for your products, equipment and safety areas that incorporate durable materials, exacting production standards and, at times, very specialized designs. For more than 45 years, Drake has earned the trust of private industries, US, state & local governments and NASA.
+ +
+
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ + + +

Products

+ +
+
+
+ +
+
+
+ +
+
+
+
+
+
+ + assetID-1 + +
+
+
Labels
+
+
+ +
+
+
+
+
+
+ + barcode-serial1 + +
+
+
Nameplates
+
+
+ +
+
+
+
+
+
+ + overlays-1 + +
+
+
Equipment Panel Overlays
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+ + membraneswitch1 + +
+
+
Membrane Switches
+
+
+ +
+
+
+
+
+
+ + custom-badges + +
+
+
OEM Bezel Re-Branding
+
+
+ +
+
+
+
+
+
+ + safetyhazard1 + +
+
+
Safety
+
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ + + +

Capabilities

+ +
+
+
+ +
+
+
+
Drake Industries offers a full range of materials and print/manufacturing capabilities that support our durable label and marking solutions. We are capable of manufacturing a variety of labels and printing on a variety of materials and films. We are a UL® certified label manufacturer, and UL® and CSA® label printer in central Texas.
+ +
+
+
+ +
+
+
+
VIEW OUR LIST
+ +
+
+
+ +
+
+ +
+
+
+
+ + + +

About Drake

+ +
+
+
+ +
+
+
+
We are a manufacturer of high-quality, durable labels, dataplates, and ID tags. Drake understands that you choose label solutions for your products, equipment and safety areas that incorporate durable materials, exacting production standards and very specialized designs. For more than 45 years, Drake has earned the trust of private industries, US, state & local governments and NASA. We’re ready to earn your trust.
+ +
+
+
+ +
+
+
+
LEARN MORE
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+ + + +

Request a Quote

+ +
+
+
+ +
+
+
+
Contact Drake to talk to an expert about your project.
+ +
+
+
+ +
+
+
+
GET A QUOTE
+ +
+
+
+ +
+
+
+ +
+
+
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +// false positives +export const a11yBlogMock = ` +Convert a Next.js app to Astro Guide
From Next.js to Astro
21/6/2022
Engineering

Converting to Astro from Next.js


If you are big into the React community you might know about the Next.js framework to build websites static and server side apps.

It provides a lot of benefits like turning a javascript react client side application that requires the user to build the html/content on the client at the server level.

You can think of it as code is shipped and ready to go without having the user have to execute client-side code to build the structure of the data or html.

From files pre-created HTML, CSS, Javascript, and other files move to a web server that can fulfill  request to browser.
Example of how code is transferred to a server so that it can move the files required to the browser. ( Picture MDN )

First glance another framework?

Initially looking into the project after cycling through the javascript world with tools that live for the moment. Astro seemed like it was very aligned with some of the concepts that

Next.js provides like static site generating (SSG) which is a huge win allowing for improved SEO and more. The idea that brought in the difference was this was not like Next.js

since Astro does not care about the language that you use and is more of a tool that is going to build all the html that can be built on the server during the build step and eliminating any unused javascript on the html that was executed on the server.

Doesn't Next.js do this too?

Well yes and no, Next.js handles this at the cost of extra javascript and bundles that execute on the page that hydrate the content from the server to allow it to still be interactive with client side required javascript (like animations and events). The page is shipped with extra code that allows for this regardless if the page has interactivity making the payload larger. With Astro the html is shipped with just the javascript that would make the page interactive and the code to launch the app, including not being tied to a set library or language. On a basic SPA website it takes about 704ms for Next.js to load while Astro takes 107ms.

Nextjs takes 16 request and loads a basic website at 704ms while Astro performs 7 request and takes 107ms.
Side by side example with Next.js on the left and Astro on the right.

Jeff Mendez personal website with 3 navigation items, a picture of Jeff Mendez fishing, and introduction. Hi, my name is Jeff Mendez and I am software engineer and Founder of A11yWatch a web accessibility improvement suite. Checkout A11yWatch to improve your web inclusion. Use the website accessibility checker for free. Github link to personal code.
Example of website tested.

Into the future!

We are very excited for Astro and looking forward to moving some of our content over. Stay tuned as we post more content about the new tool that can help developers keep their productivity and also ship small bundles. A migration of the example can be found here to give an idea on the effort it would take to move a simple page. It took around 20 mins from initially reading the docs to moving the entire application over. The website of the Next.js to Astro conversion can be pulled from to use providing a typescript setup.


Jeff MendezJeff Mendez

My name is Jeff and I am the founder and creator of A11yWatch.

+ +"###; diff --git a/kayle_innate/tests/web.rs b/kayle_innate/tests/web.rs index cc3ae970..fe76b7d4 100644 --- a/kayle_innate/tests/web.rs +++ b/kayle_innate/tests/web.rs @@ -3,6 +3,8 @@ #![cfg(target_arch = "wasm32")] extern crate wasm_bindgen_test; +mod mock; + use kayle_innate::get_document_links; use wasm_bindgen_test::*; @@ -15,8 +17,8 @@ fn _get_document_links() {
- Home - About + Home + About
@@ -38,10 +40,10 @@ fn _get_document_links() {
- Home - About - Magic - Meta + Home + About + Magic + Meta
@@ -65,41 +67,5 @@ fn _get_document_links() { #[wasm_bindgen_test] #[cfg(feature = "accessibility")] fn _parse_accessibility_tree() { - kayle_innate::parse_accessibility_tree( - r#" - - - My website - - - - - -
- -
-
-

Some nice content

-

Content ipsum

- -
- - - "#, - ); + kayle_innate::parse_accessibility_tree(mock::MOCK_WEBSITE_HTML); } diff --git a/package.json b/package.json index b233db86..7d18f6cc 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "pub:fast_htmlcs": "yarn build:fast_htmlcs && yarn npm publish", "pub:fast_axecore": "yarn build:fast_axecore && yarn npm publish", "pub:kayle": "yarn build:kayle && yarn npm publish", - "fix": "npx prettier --write '**/*.{ts,tsx,md}'" + "fix": "npx prettier --write '**/*.{ts,tsx,md}'", + "test:innate": "cd kayle_innate && RUST_LOG=info wasm-pack test --node --firefox --headless --release" } }