@uuv/a11y
Version:
A javascript lib for running a11y validation based on multiple reference(RGAA, etc)
764 lines • 63.9 kB
JavaScript
"use strict";
// import { A11yReference } from "../../model/reference";
// import { AutoCheckA11yRule } from "../../model/rule";
// import { ByTagQuery } from "../../query";
//
// export const A11Y_ALIX_RULES : A11yReference = {
// name: "ALIX",
// version: "4.1",
// rules: [
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Attribute should not contain whitespace",
// wcag: "",
// id: "",
// elementType: "error - attribute-whitespace",
// query: new ByTagQuery([
// "[id*=\" \"], [lang*=\" \"], map[name*=\" \"]"
// ]),
// description: "Some HTML attributes should not contain any whitespace —namely [id], [lang] and map[name].",
// help: "https://html.spec.whatwg.org/#the-id-attribute\nhttps://html.spec.whatwg.org/#the-map-element"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "[tabindex] > 0",
// wcag: "",
// id: "",
// elementType: "error - tab-order",
// query: new ByTagQuery(["[tabindex]:not([tabindex=\"0\"], [tabindex^=\"-\"])"]),
// description: "The [tabindex] attribute should never be greater than 0.",
// help: "https://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L337\nhttps://www.w3.org/WAI/WCAG21/Techniques/failures/F44\nhttps://www.scottohara.me/blog/2019/05/25/tabindex.html"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Empty [href]",
// wcag: "",
// id: "",
// elementType: "error - empty-href",
// query: new ByTagQuery(["a[href=\"\"], a[href=\" \"]"]),
// description: "The [href] attribute, if present, should not be empty. A link to something, right?",
// help: "https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements\nhttps://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L161\nhttps://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L165"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Empty link",
// wcag: "",
// id: "",
// elementType: "error - empty-link",
// query: new ByTagQuery(["a:empty[title=\"\"], a:empty[aria-label=\"\"], a:empty[aria-labelledby=\"\"], a:empty:not([title], [aria-label], [aria-labelledby])"]),
// description: "An empty link should have a label, within [title], [aria-label] or targeted by [aria-labelledby]. By the way, why would you use an empty link?",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#6.2\nhttps://www.w3.org/TR/WCAG21/#non-text-content\nhttps://www.w3.org/TR/WCAG21/#link-purpose-in-context\nhttps://www.w3.org/TR/WCAG21/#link-purpose-link-only\nhttps://www.w3.org/WAI/WCAG21/Techniques/html/H30\nhttps://www.w3.org/WAI/WCAG21/Techniques/general/G91\nhttps://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L193"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Missing alternative for img",
// wcag: "",
// id: "",
// elementType: "error - no-alt",
// query: new ByTagQuery(["img[alt=\" \"], area[alt=\" \"], input[type=\"image\"][alt=\" \"], img:not([alt]), area:not([alt]), input[type=\"image\"]:not([alt])"]),
// description: "An <img> must have an [alt]. Always.",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#1.1\nhttps://www.w3.org/WAI/tutorials/images/decision-tree/\nhttps://html.spec.whatwg.org/multipage/images.html#alt\nhttps://www.w3.org/TR/WCAG21/#non-text-content\nhttps://www.w3.org/WAI/WCAG21/Techniques/html/H36\nhttps://www.w3.org/WAI/WCAG21/Techniques/html/H37\nhttps://www.w3.org/WAI/WCAG21/Techniques/html/H24\nhttps://www.w3.org/WAI/WCAG21/Techniques/failures/F65"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Missing label for [role=img]",
// wcag: "",
// id: "",
// elementType: "error - no-aria-label",
// query: new ByTagQuery(["[role=\"img\"]:not([aria-hidden=\"true\"], [aria-label], [aria-labelledby]), svg[role=\"img\"]:not([aria-hidden=\"true\"], [aria-label], [aria-labelledby])"]),
// description: "[role=img] without [aria-hidden=true] should either have [aria-label] or [aria-labelledby]. If image is decorative, please use [role=presentation] instead.",
// help: "https://www.w3.org/TR/wai-aria-1.2/#img\nhttps://www.w3.org/TR/WCAG21/#non-text-content\nhttps://www.w3.org/WAI/tutorials/images/decision-tree/\nhttps://www.w3.org/wai-aria-1.2/#presentation"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Missing source for img",
// wcag: "",
// id: "",
// elementType: "error - no-src",
// query: new ByTagQuery(["img:not([src], [srcset]), img[src=\"\"], img[src=\" \"], img[src=\"#\"], img[src=\"/\"], img[srcset=\"\"], img[srcset=\" \"], img[srcset=\"#\"], img[srcset=\"/\"], input[type=\"image\"]:not([src], [srcset]), input[type=\"image\"][src=\"\"], input[type=\"image\"][src=\" \"], input[type=\"image\"][src=\"#\"], input[type=\"image\"][src=\"/\"], input[type=\"image\"][srcset=\"\"], input[type=\"image\"][srcset=\" \"], input[type=\"image\"][srcset=\"#\"], input[type=\"image\"][srcset=\"/\"]"]),
// description: "An <img> must have an [src] or an [srcset], and it should be a valid one. Obviously.",
// help: "https://html.spec.whatwg.org/multipage/embedded-content.html#attr-img-src\nhttps://scottjehl.github.io/picturefill/"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "A label with an empty [for] attribute",
// wcag: "",
// id: "",
// elementType: "error - empty-for",
// query: new ByTagQuery(["label[for=\"\"], label[for=\" \"]"]),
// description: "A <label> with a [for] attribute should label something with an [id] attribute, obviously.",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#11.1.2\nhttps://github.com/DISIC/rgaa_referentiel_en/blob/44e2bee0c710e37ca49901b1e6b8fae9b553fd5d/criteria.html#L3981\nhttps://www.w3.org/WAI/WCAG21/Techniques/html/H44\nhttps://www.w3.org/WAI/tutorials/forms/labels/\nhttps://make.wordpress.org/accessibility/2017/01/16/testing-form-functionality-with-different-assistive-technology/\nhttps://www.w3.org/TR/WCAG21/#labels-or-instructions\nhttps://www.w3.org/TR/WCAG21/#headings-and-labels\nhttps://www.w3.org/TR/WCAG21/#info-and-relationships"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Missing some kind of label",
// wcag: "",
// id: "",
// elementType: "error - no-id",
// query: new ByTagQuery(["input:not([type=\"button\"], [type=\"submit\"], [type=\"hidden\"], [type=\"reset\"], [type=\"image\"], [id], [aria-label], [title], [aria-labelledby]), textarea:not([id], [aria-label], [aria-labelledby]), select:not([id], [aria-label], [aria-labelledby])"]),
// description: "How to label a field? You have a few choices: [id], [title], [aria-label], and [aria-labelledby].",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#11.1\nhttps://www.w3.org/TR/WCAG21/#labels-or-instructions\nhttps://www.w3.org/TR/WCAG21/#headings-and-labels\nhttps://www.w3.org/TR/WCAG21/#info-and-relationships\nhttps://www.w3.org/WAI/WCAG21/Techniques/html/H44"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Missing a value",
// wcag: "",
// id: "",
// elementType: "error - no-value",
// query: new ByTagQuery(["input[type=\"reset\"]:not([value], [title], [aria-label], [aria-labelledby]), input[type=\"submit\"]:not([value], [title], [aria-label], [aria-labelledby]), input[type=\"button\"]:not([value], [title], [aria-label], [aria-labelledby])"]),
// description: "How to label a [reset], [submit] or [button] type input? You still have a few choices: [value], [title], [aria-label], and [aria-labelledby].",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#11.9\nhttps://www.w3.org/TR/WCAG21/#name-role-value\nhttps://www.w3.org/WAI/WCAG21/Techniques/html/H91"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Empty button",
// wcag: "",
// id: "",
// elementType: "error - empty-button",
// query: new ByTagQuery(["button:empty:not([aria-label], [aria-labelledby], [title])"]),
// description: "A <button> should either have content or an [aria-label], [aria-labelledby] or [title]. Those attributes, if present, should not be empty.",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#11.9\nhttps://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#11\nhttps://www.w3.org/TR/WCAG21/#name-role-value\nhttps://www.w3.org/WAI/WCAG21/Techniques/html/H91\nhttps://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L193"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Empty button attribute",
// wcag: "",
// id: "",
// elementType: "error - empty-button-attr",
// query: new ByTagQuery(["button[title=\"\"], button[aria-label=\"\"], button[aria-labelledby=\"\"]"]),
// description: "[aria-label], [aria-labelledby] or [title] on a <button> must not be empty.",
// help: ""
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Form button",
// wcag: "",
// id: "",
// elementType: "error - not-form-button",
// query: new ByTagQuery(["button:not([type], [form], [formaction], [formtarget])"]),
// description: "A `<button>` has a default `[type]` value of \"submit\", in order to send a `<form>`. However, outside a form, if it's intended to send a form, it should mention it with one of those attributes: `[form]`, `[formaction]`, `[formtarget]`. If it doesn't submit anything, it should have the `[type=\"button\"].",
// help: "<https://html.spec.whatwg.org/multipage/forms.html#the-button-element>\n<https://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L189>"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Button not submitting",
// wcag: "",
// id: "",
// elementType: "error - not-submit-button",
// query: new ByTagQuery(["button[type=\"reset\"], button[type=\"button\"]"]),
// description: "If a `<button>`'s `[type]` is either \"reset\" or \"button\", it should not use the following attributes: [formmethod], [formaction], [formtarget], [formenctype], [formnovalidate].",
// help: "<https://html.spec.whatwg.org/multipage/forms.html#the-button-element>"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Disabled button",
// wcag: "",
// id: "",
// elementType: "error - disabled-button",
// query: new ByTagQuery(["button[class*=\"disabled\"]:not([disabled], [readonly])"]),
// description: "A `<button>` styled to be disabled should be disabled *for real*. Use `[disabled]` and `[readonly].",
// help: "<https://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L122>"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "input without [type]",
// wcag: "",
// id: "",
// elementType: "error - no-type",
// query: new ByTagQuery(["input:not([type]), input[type=\" \"], input[type=\"\"]"]),
// description: "`<input>` needs a `[type]` in order to tell the user what kind of data is wanted.",
// help: "<https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#11.11>\n<https://www.w3.org/TR/WCAG21/#error-suggestion>"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "optgroup without label",
// wcag: "",
// id: "",
// elementType: "error - optgroup",
// query: new ByTagQuery(["optgroup:not([label])"]),
// description: "`<optgroup>` needs a `[label]` to explain what's inside the group.",
// help: "<https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#11.8>\n<https://www.w3.org/WAI/WCAG21/Techniques/html/H85>\n<https://www.w3.org/TR/2014/NOTE-WCAG20-TECHS-20140916/H85>"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "iframe without [title]",
// wcag: "",
// id: "",
// elementType: "error - no-title",
// query: new ByTagQuery(["iframe:not([title]), iframe[title=\" \"], iframe[title=\"\"]"]),
// description: "`<iframe>` needs a `[title]` in order to tell the user what to expect inside the iframe.",
// help: "<https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#2.1>\n<https://www.w3.org/TR/WCAG21/#name-role-value>\n<https://www.w3.org/WAI/WCAG21/Techniques/html/H64>"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "form missing an [action]",
// wcag: "",
// id: "",
// elementType: "error - no-action",
// query: new ByTagQuery(["form:not([action]), form[action=\" \"], form[action=\"\"]"]),
// description: "`<form>` should do something, isn't it? Well, `[action]` is meant to define what.",
// help: "<https://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L214>"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "No valid language defined",
// wcag: "",
// id: "",
// elementType: "error - no-lang",
// query: new ByTagQuery(["html:not([lang]), html[lang*=\" \"], html[lang=\"\"]"]),
// description: "`<html>` must indicate to User Agents the human language used in the document.",
// help: "<https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#8.3>\n<https://accessibilite.numerique.gouv.fr/methode/glossaire/#langue-par-defaut>\n<https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#8.4>\n<https://www.w3.org/TR/WCAG21/#language-of-page>\n<https://www.w3.org/WAI/WCAG21/Techniques/html/H57>\n<https://html.spec.whatwg.org/#attr-lang>\n<https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang>\n<https://www.w3.org/WAI/WCAG21/Understanding/language-of-page>\n<https://www.w3.org/WAI/WCAG21/Understanding/language-of-parts.html>\n<https://www.matuzo.at/blog/lang-attribute/>\n<https://codepen.io/matuzo/project/editor/ZyrVee>"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "table used for layout",
// wcag: "",
// id: "",
// elementType: "error - table-for-layout",
// query: new ByTagQuery(["table[role=\"presentation\"] th, table[role=\"presentation\"] thead, table[role=\"presentation\"] tfoot, table[role=\"presentation\"] caption, table[role=\"presentation\"] colgroup, table[role=\"presentation\"] [axis], table[role=\"presentation\"] [scope], table[role=\"presentation\"] [headers]"]),
// description: "`<table>` may be used for layout if a [role=\"presentation\"] is added. However, semantics tags and attributes aiming to organize data mustn't be used. Here's a list: <th>, <thead>, <tfoot>, <caption>, [axis], [scope], [headers], [colgroup].",
// help: "<https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#5.8>\n<https://www.w3.org/WAI/WCAG21/Techniques/failures/F46>\n<https://www.w3.org/WAI/WCAG21/Techniques/failures/F49>\n<https://www.w3.org/TR/WCAG21/#info-and-relationships>"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "[width] & [height] attributes",
// wcag: "",
// id: "",
// elementType: "error - dimensions",
// query: new ByTagQuery([":not(img, object, embed, svg, canvas)[width], :not(img, object, embed, svg, canvas)[height]"]),
// description: "`[width]` and `[height]` are presentation information. Therefore, they shouldn't be used in markup, except for `<img>`. Use CSS instead.",
// help: "<https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#10>\n<https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#10.1>\n<https://www.w3.org/TR/WCAG21/#info-and-relationships>\n<https://www.w3.org/TR/WCAG21/#meaningful-sequence>"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Javascript events attributes",
// wcag: "",
// id: "",
// elementType: "error - js-events",
// query: new ByTagQuery(["[onafterprint], [onbeforeprint], [onbeforeunload], [onerror], [onhaschange], [onload], [onmessage], [onoffline], [ononline], [onpagehide], [onpageshow], [onpopstate], [onredo], [onresize], [onstorage], [onundo], [onunload], [onblur], [onchage], [oncontextmenu], [onfocus], [onformchange], [onforminput], [oninput], [oninvalid], [onreset], [onselect], [onsubmit], [onkeydown], [onkeypress], [onkeyup], [onclick], [ondblclick], [ondrag], [ondragend], [ondragenter], [ondragleave], [ondragover], [ondragstart], [ondrop], [onmousedown], [onmousemove], [onmouseout], [onmouseover], [onmouseup], [onmousewheel], [onscroll], [onabort], [oncanplay], [oncanplaythrough], [ondurationchange], [onemptied], [onended], [onerror], [onloadeddata], [onloadedmetadata], [onloadstart], [onpause], [onplay], [onplaying], [onprogress], [onratechange], [onreadystatechange], [onseeked], [onseeking], [onstalled], [onsuspend], [ontimeupdate], [onvolumechange], [onwaiting]"]),
// description: "Javascript event attributes (such as `[onmouseover]`) should not be used. Prefer either CSS pseudo-classes (`:hover`, `:focus`, `:active`, etc.) or JS event listeners.",
// help: "<https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes>\n<https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener>"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Namespaces",
// wcag: "",
// id: "",
// elementType: "error - namespace",
// query: new ByTagQuery(["[id^='1'],[id^='2'],[id^='3'],[id^='4'],[id^='5'],[id^='6'],[id^='7'],[id^='8'],[id^='9'],[id^='0'],[id^='--'],[id^='-1'],[id^='-2'],[id^='-3'],[id^='-4'],[id^='-5'],[id^='-6'],[id^='-7'],[id^='-8'],[id^='-9'],[id^='-0'],[class^='1'],[class^='2'],[class^='3'],[class^='4'],[class^='5'],[class^='6'],[class^=''],[class^='8'],[class^='9'],[class^='0'],[class^='--'],[class^='-1'],[class^='-2'],[clas^='-3'],[class^='-4'],[class^='-5'],[class^='-6'],[class^='-7'],[class^='-8'],[class^='-9'],[class^='-0']"]),
// description: "Did you know that some characters should be avoided as first characters in class names and identifiers? Yep. Digits, two hyphens, or hyphen followed by a digit.",
// help: [
// "https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#w3cselgrammar",
// "https://www.w3.org/Style/CSS/Test/CSS3/Selectors/current/",
// "https://www.w3.org/Style/CSS/Test/CSS3/Selectors/current/html/tests/css3-modsel-175a.html"
// ]
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Unaccessible viewport attribute",
// wcag: "",
// id: "",
// elementType: "error - unaccessible-viewport",
// query: new ByTagQuery(["meta[name='viewport'][content*='maximum-scale'], meta[name='viewport'][content*='minimum-scale'], meta[name='viewport'][content*='user-scalable=no']"]),
// description: "User should be able to zoom in or out the page to improve readability and comfort; this is usually allowed by the viewport <meta>.",
// help: [
// "https://bitsofco.de/linting-html-using-css/",
// "https://dequeuniversity.com/rules/axe/2.1/meta-viewport",
// "https://www.w3.org/TR/WCAG21/#resize-text"
// ]
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Incorrect charset",
// wcag: "",
// id: "",
// elementType: "error - incorrect-charset",
// query: new ByTagQuery(["meta[charset]:not([charset='utf-8'], [charset='UTF-8'])"]),
// description: "Using utf-8 character encoding is recommended by the W3C itself. Supports many languages and can accommodate pages and forms in any mixture of those languages.",
// help: [
// "https://bitsofco.de/linting-html-using-css/#incorrectcharacterset",
// "https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-charset"
// ]
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Charset should come first",
// wcag: "",
// id: "",
// elementType: "error - late-charset",
// query: new ByTagQuery(["head :first-child:not([charset])"]),
// description: "The <meta> element declaring the encoding must be inside the <head> element and within the first 1024 bytes of the HTML.",
// help: "https://bitsofco.de/linting-html-using-css/#incorrectcharacterset"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Invalid [dir] attribute",
// wcag: "",
// id: "",
// elementType: "error - invalid-dir",
// query: new ByTagQuery(["[dir]:not([dir='rtl'], [dir='ltr'], [dir='auto'])"]),
// description: "The [dir] attribute only accepts three values: rtl, ltr, and auto.",
// help: [
// "https://www.w3.org/International/questions/qa-html-dir",
// "https://www.w3.org/International/articles/inline-bidi-markup/#dirattribute"
// ]
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "[accesskey] is a bad idea",
// wcag: "",
// id: "",
// elementType: "error - accesskey",
// query: new ByTagQuery(["[accesskey]"]),
// description: "The [accesskey] attribute is meant to implement site-specific keyboard shortcuts. This is usually a bad idea since keys might be already used by either the operating system, the browser, browser extension, and even user's settings.",
// help: "https://jkorpela.fi/forms/accesskey.html"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Grouping inputs",
// wcag: "",
// id: "",
// elementType: "error - inputs-group",
// query: new ByTagQuery(["input[type='radio']:not([name]), input[type='checkbox']:not(:only-of-type, [name])"]),
// description: "Inputs with a type of radio or checkbox are usually grouped. The [name] attribute is meant to programmatically associate them, thus is needed.",
// help: "https://www.w3.org/WAI/tutorials/forms/grouping/"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "[radio] outside a fieldset",
// wcag: "",
// id: "",
// elementType: "error - radio-group",
// query: new ByTagQuery(["input[type='radio']"]),
// description: "Inputs with a type of radio should be grouped by a parent <fieldset>, described by its <legend>.",
// help: "https://www.w3.org/WAI/tutorials/forms/grouping/#radio-buttons"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "[role=slider] missing attributes",
// wcag: "",
// id: "",
// elementType: "error - role-slider",
// query: new ByTagQuery(["[role='slider']:not([aria-valuemin]), [role='slider']:not([aria-valuemax]), [role='slider']:not([aria-valuenow])"]),
// description: "[role='slider'] requires a few attributes: [aria-valuemin], [aria-valuemax], [aria-valuenow].",
// help: "https://www.w3.org/TR/wai-aria-1.2/#slider"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "[role=spinbutton] missing attributes",
// wcag: "",
// id: "",
// elementType: "error - role-spinbutton",
// query: new ByTagQuery(["[role='spinbutton']:not([aria-valuemin]), [role='spinbutton']:not([aria-valuemax]), [role='spinbutton']:not([aria-valuenow])"]),
// description: "[role='spinbutton'] requires a few attributes: [aria-valuemin], [aria-valuemax], [aria-valuenow].",
// help: "https://www.w3.org/TR/wai-aria-1.2/#spinbutton"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "[role=checkbox] missing state",
// wcag: "",
// id: "",
// elementType: "error - role-checkbox",
// query: new ByTagQuery(["[role='checkbox']:not([aria-checked])"]),
// description: "[role='checkbox'] requires an attribute: [aria-checked].",
// help: "https://www.w3.org/TR/wai-aria-1.2/#checkbox"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "[role=combobox] missing [state]",
// wcag: "",
// id: "",
// elementType: "error - role-combobox",
// query: new ByTagQuery(["[role='combobox']:not([aria-expanded])"]),
// description: "[role='combobox'] requires an attribute: [aria-expanded].",
// help: "https://www.w3.org/TR/wai-aria-1.2/#combobox"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "[role=scrollbar] required properties",
// wcag: "",
// id: "",
// elementType: "error - role-scrollbar",
// query: new ByTagQuery(["[role='scrollbar']:not([aria-controls]), [role='scrollbar']:not([aria-valuemin]), [role='scrollbar']:not([aria-valuemax]), [role='scrollbar']:not([aria-valuenow]), [role='scrollbar']:not([aria-orientation])"]),
// description: "Some properties are required to comply the [role='scrollbar'] pattern: [aria-controls], [aria-valuemin], [aria-valuemax], [aria-valuenow], [aria-orientation].",
// help: "https://www.w3.org/TR/wai-aria-1.2/#scrollbar"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Nested interactive elements",
// wcag: "",
// id: "",
// elementType: "error - nested-interactive",
// query: new ByTagQuery(["a a[href], button a[href], a audio[controls], button audio[controls], a video[controls], button video[controls], a button, button button, a details, button details, a embed, button embed, a iframe, button iframe, a img[usemap], button img[usemap], a label, button label, a select, button select, a textarea, button textarea, a input[type]:not([hidden]), button input[type]:not([hidden]), form form, label label, meter meter, progress progress"]),
// description: "An interactive element should not be contained in another interactive element (e.g. <a> in <button>).",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#8.2"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Invalid nesting in a list",
// wcag: "",
// id: "",
// elementType: "warning - invalid-list-nesting",
// query: new ByTagQuery(["ul > :not(li), ol > :not(li), :not(ul, ol) > li"]),
// description: "The only child allowed in <ul> and <ol> is <li> - and the converse is also true.",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#8.2"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Invalid sibling in a definition list",
// wcag: "",
// id: "",
// elementType: "warning - invalid-def",
// query: new ByTagQuery(["dt + :not(dd), :not(dt, dd) + dd"]),
// description: "<dt> and <dd> should be direct adjacent siblings, and nothing else. Although multiple <dd> may follow a single <dt>.",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#8.2"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Invalid nesting in a definition list",
// wcag: "",
// id: "",
// elementType: "warning - invalid-def-nesting",
// query: new ByTagQuery([":not(dl) > dt, :not(dl) > dd, dl > :not(dt, dd, div)"]),
// description: "<div>, <dt> and <dd> should be direct children of <dl>. Any other imbrication may be a crime somewhere.",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#8.2"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "figcaption outside a figure",
// wcag: "",
// id: "",
// elementType: "warning - invalid-figcaption-nesting",
// query: new ByTagQuery([":not(figure) > figcaption"]),
// description: "<figcaption> doesn't make sense outside a <figure>.",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#8.2"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "figure without the group ARIA role",
// wcag: "",
// id: "",
// elementType: "warning - figure-role",
// query: new ByTagQuery(["figure:not([role=\"group\"])"]),
// description: "<figure> needs [role=\"group\"] for accessibility reason.",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#1.9"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Invalid nesting",
// wcag: "",
// id: "",
// elementType: "warning - invalid-nesting",
// query: new ByTagQuery(["nav main, aside main, footer main, header main, article main, :not(tr) > td, :not(tr) > th, colgroup *:not(col), :not(colgroup) > col, tr > :not(td, th), optgroup > :not(option), :not(select) > optgroup, :not(fieldset) > legend, select > :not(option, optgroup), table > *:not(thead, tfoot, tbody, tr, colgroup, caption), address h1, address h2, address h3, address h4, address h5, address h6, address nav, address aside, address header, address footer, address address, address article, address section"]),
// description: "Some nestings are forbidden, and do not have their own test case for now.",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#8.2"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Misplaced div",
// wcag: "",
// id: "",
// elementType: "warning - misplaced-div",
// query: new ByTagQuery(["b div, i div, q div, em div, abbr div, cite div, code div, span div, small div, label div, strong div"]),
// description: "Did you know that you shouldn't add a <div> inside any inline element? You could use a <span> instead.",
// help: "https://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L326"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Misused sectioning tags",
// wcag: "",
// id: "",
// elementType: "warning - sectioning-tags",
// query: new ByTagQuery(["aside > aside:first-child, article > aside:first-child, aside > article:first-child, aside > section:first-child, section > section:first-child, article > section:first-child, article > article:first-child"]),
// description: "<section>, <aside>, <article> are sectioning tags. They must not be used as wrappers!",
// help: "https://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L252"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "legend must be a fieldset's:first-child",
// wcag: "",
// id: "",
// elementType: "warning - fieldset",
// query: new ByTagQuery(["fieldset > *:not(legend):first-child, fieldset > legend:not(:first-child)"]),
// description: "<legend> must be the first child of a <fieldset>.",
// help: "https://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L292"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "label must wrap an interactive element",
// wcag: "",
// id: "",
// elementType: "warning - label-wrap",
// query: new ByTagQuery(["label:has(button, details, input, select, textarea, a, area, fieldset, keygen, object, output, progress, video)"]),
// description: "<label> must wrap an interactive element.",
// help: "https://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L321"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "[role=presentation] shouldn't be used on image",
// wcag: "",
// id: "",
// elementType: "warning - presentation",
// query: new ByTagQuery(["img[role=\"presentation\"], svg[role=\"presentation\"], area[role=\"presentation\"], embed[role=\"presentation\"], canvas[role=\"presentation\"], object[role=\"presentation\"]"]),
// description: "Any decorative image should be marked up with [aria-hidden=\"true\"] (or empty [alt] if <img>). [role=presentation] shall do the trick but at the time of writing, its support is too low compared to empty [alt] or [aria-hidden=true].",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#1.2"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "A role is needed for svg",
// wcag: "",
// id: "",
// elementType: "warning - no-aria-role",
// query: new ByTagQuery(["svg:not([aria-hidden=\"true\"], [role=\"img\"])"]),
// description: "Any <svg> should either have [aria-hidden=\"true\"] if decorative, or a [role=\"img\"] if informative.",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#1.2"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "[autoplay] should probably not be used",
// wcag: "",
// id: "",
// elementType: "warning - autoplay",
// query: new ByTagQuery(["video[autoplay], audio[autoplay]"]),
// description: "A time-based media like <audio> or <video> should not [autoplay], because it can be quite surprising for the user.",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#4.10"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "[controls] would be helpful",
// wcag: "",
// id: "",
// elementType: "warning - controls",
// query: new ByTagQuery(["video:not([controls]), audio:not([controls])"]),
// description: "A time-based media like <audio> or <video> would be easier to use if [controls] are activated for the user.",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#4.11"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Most of DOM nodes shouldn't be :empty",
// wcag: "",
// id: "",
// elementType: "warning - empty-nodes",
// query: new ByTagQuery(["body *:empty:not([hidden], [aria-hidden], [src], button, a, iframe, textarea, area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, track, wbr, title)"]),
// description: "Obviously void elements are empty, as well as <iframe> and <textarea> could be :empty. Any other :empty tag that is not hidden is probably useless, and should be deleted.",
// help: "https://github.com/Heydon/REVENGE.CSS/blob/master/revenge.css#L243"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "A single line table may be used for layout",
// wcag: "",
// id: "",
// elementType: "warning - table-layout",
// query: new ByTagQuery(["table:not([role=\"presentation\"]) > tr:only-child, table:not([role=\"presentation\"]) > tbody > tr:only-child"]),
// description: "A lonely <tr> can be a symptom of a table used for layout. Should be double checked!",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#5.3"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Nested tables",
// wcag: "",
// id: "",
// elementType: "warning - nested-table",
// query: new ByTagQuery(["table table"]),
// description: "Nested <table> may confuse users. Is it what you meant?",
// help: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#5.2"
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Obsolete tags in HTML5",
// wcag: "",
// id: "",
// elementType: "obsolete - tags obsolete",
// query: new ByTagQuery([
// "applet",
// "acronym",
// "bgsound",
// "dir",
// "frame",
// "frameset",
// "noframes",
// "hgroup",
// "isindex",
// "listing",
// "nextid",
// "noembed",
// "plaintext",
// "rb",
// "rtc",
// "strike",
// "xmp",
// "basefont",
// "big",
// "blink",
// "center",
// "font",
// "marquee",
// "multicol",
// "nobr",
// "spacer",
// "tt",
// "keygen",
// "menu",
// "menuitem"
// ]),
// description: "Many, many tags are obsolete in HTML5. You should care!",
// help: [
// "<https://html.spec.whatwg.org/multipage/obsolete.html#obsolete>",
// "<https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#8.2>"
// ]
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Obsolete attributes in HTML5",
// wcag: "",
// id: "",
// elementType: "obsolete - attributes obsolete",
// query: new ByTagQuery([
// "[dropzone]",
// "a[charset], link[charset]",
// "a[coords]",
// "a[shape]",
// "a[methods], link[methods]",
// "a[name], embed[name], img[name], option[name]",
// "a[rev], link[rev]",
// "a[urn], link[urn]",
// "form[accept]",
// "area[nohref]",
// "area[type]",
// "area[hreflang]",
// "head[profile]",
// "html[version]",
// "input[ismap]",
// "input[usemap]",
// "input[inputmode]",
// "iframe[longdesc], img[longdesc]",
// "img[lowsrc]",
// "link[target]",
// "meta[scheme]",
// "meta[http-equiv='content-language']",
// "meta[http-equiv='content-type']",
// "meta[http-equiv='set-cookie']",
// "object[archive]",
// "object[classid]",
// "object[code]",
// "object[codebase]",
// "object[codetype]",
// "object[declare]",
// "object[standby]",
// "param[type]",
// "param[valuetype]",
// "script[language]",
// "script[event]",
// "script[for]",
// "table[datapagesize]",
// "table[summary]",
// "td[axis], th[axis]",
// "td[scope]",
// "td[abbr]",
// "a[datasrc], applet[datasrc], button[datasrc], div[datasrc], frame[datasrc], iframe[datasrc], img[datasrc], input[datasrc], label[datasrc], legend[datasrc], marquee[datasrc], object[datasrc], option[datasrc], select[datasrc], span[datasrc], table[datasrc], textarea[datasrc]",
// "a[datafld], applet[datafld], button[datafld], div[datafld], fieldset[datafld], frame[datafld], iframe[datafld], img[datafld], input[datafld], label[datafld], legend[datafld], marquee[datafld], object[datafld], param[datafld], select[datafld], span[datafld], textarea[datafld]",
// "button[dataformatas], div[dataformatas], input[dataformatas], label[dataformatas], legend[dataformatas], marquee[dataformatas], object[dataformatas], option[dataformatas], select[dataformatas], span[dataformatas], table[dataformatas]",
// "body[alink]",
// "body[bgcolor], table[bgcolor], td[bgcolor], th[bgcolor], tr[bgcolor]",
// "body[link]",
// "body[marginbottom]",
// "body[marginheight], iframe[marginheight]",
// "body[marginleft]",
// "body[marginright]",
// "body[margintop]",
// "body[marginwidth], iframe[marginwidth]",
// "body[text]",
// "body[vlink]",
// "br[clear]",
// "col[char], tbody[char], thead[char], tfoot[char], td[char], th[char], tr[char]",
// "col[charoff], tbody[charoff], thead[charoff], tfoot[charoff], td[charoff], th[charoff], tr[charoff]",
// "col[valign], tbody[valign], thead[valign], tfoot[valign], td[valign], th[valign], tr[valign]",
// "col[width], hr[width], pre[width], table[width], td[width], th[width]",
// "dl[compact], ol[compact], ul[compact]",
// "embed[hspace], iframe[hspace], input[hspace], img[hspace], object[hspace]",
// "embed[vspace], iframe[vspace], input[vspace], img[vspace], object[vspace]",
// "hr[color]",
// "hr[noshade]",
// "hr[size]",
// "h1[align], h2[align], h3[align], h4[align], h5[align], h6[align], iframe[align], caption[align], col[align], div[align], embed[align], hr[align], input[align], img[align], legend[align], object[align], p[align], table[align], tbody[align], thead[align], tfoot[align], td[align], th[align], tr[align]",
// "iframe[allowtransparency]",
// "iframe[frameborder]",
// "iframe[framespacing]",
// "iframe[scrolling]",
// "img[border], object[border]",
// "li[type], ul[type]",
// "table[cellpadding]",
// "table[cellspacing]",
// "table[frame]",
// "table[rules]",
// "td[height], th[height]",
// "td[nowrap], th[nowrap]",
// "body[background], table[background], thead[background], tbody[background], tfoot[background], tr[background], td[background], th[background]",
// "embed[name], img[name]",
// "area[nohref]",
// "area[type]",
// "area[hreflang]",
// "input[ismap]",
// "input[usemap]",
// "iframe[longdesc], img[longdesc]",
// "img[lowsrc]",
// "object[archive]",
// "object[classid]",
// "object[code]",
// "object[codebase]",
// "object[codetype]",
// "object[declare]",
// "object[standby]",
// "iframe[datasrc], img[datasrc], input[datasrc],object[datasrc], select[datasrc], textarea[datasrc]",
// "iframe[datafld], img[datafld], input[datafld], object[datafld], select[datafld], textarea[datafld]",
// "input[dataformatas], object[dataformatas], select[dataformatas]",
// "iframe[marginheight]",
// "iframe[marginwidth]",
// "br[clear]",
// "hr[width]",
// "embed[hspace], iframe[hspace], input[hspace], img[hspace], object[hspace]",
// "embed[vspace], iframe[vspace], input[vspace], img[vspace], object[vspace]",
// "hr[color]",
// "hr[noshade]",
// "hr[size]",
// "iframe[align], embed[align], hr[align], input[align], img[align], object[align]",
// "iframe[allowtransparency]",
// "iframe[frameborder]",
// "iframe[framespacing]",
// "iframe[scrolling]",
// "img[border], object[border]",
// "input[inputmode]",
// "link[charset], link[methods]",
// "link[rev], link[urn]",
// "link[target]",
// "meta[scheme]",
// "meta[http-equiv='content-language']",
// "meta[http-equiv='content-type']",
// "meta[http-equiv='set-cookie']",
// "script[language]",
// "script[event]",
// "script[for]"
// ]),
// description: "Many, many attributes are obsolete in HTML5. You should care!",
// help: [
// "<https://html.spec.whatwg.org/multipage/obsolete.html#obsolete>",
// "<https://html.spec.whatwg.org/multipage/obsolete.html#non-conforming-features>",
// "<https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#8.2>",
// "<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta>"
// ]
// }),
// AutoCheckA11yRule.from({
// reference: "a11y.css",
// criterion: "Empty <select> should start with an empty <option>'s [value]",
// wcag: "",
// id: "",
// elementType: "advice - empty-option-on-select",
// query: new ByTagQuery(["select[required]:not([multiple])[size='1'], select[required]:not([multiple], [size])"]),
// description: "A <select required> element, which isn't [multiple] and whose [size] isn't greater than 1, should start with an empty <option>. That being said, you may use a placeholder content for this option but must ensure to use an empty [value] attribute; or set a [size] attribute to the <select>, which value should equal to the number of <option>s.",
// help: [
// "https://html.spec.whatwg.org/multipage/form-elements.html#placeholder-label-option",
// "https://validator.w3.org/nu/?showsource=yes&doc=https%3A%2F%2Fjsbin.com%2Ftozopid%2Fquiet"
// ]
// }),
// AutoCheckA11yRule.from({
//