From 125191a843ef4ce41b74b335a4bb44ec3fc0e0d6 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 3 Sep 2017 17:35:34 -0400 Subject: [PATCH] aria-props --- src/validate/html/a11y.ts | 20 ++++++++++++++----- .../samples/a11y-aria-props/input.html | 1 + .../samples/a11y-aria-props/warnings.json | 19 ++++++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 test/validator/samples/a11y-aria-props/input.html create mode 100644 test/validator/samples/a11y-aria-props/warnings.json diff --git a/src/validate/html/a11y.ts b/src/validate/html/a11y.ts index c7d50f17e3..4cb1c0be8e 100644 --- a/src/validate/html/a11y.ts +++ b/src/validate/html/a11y.ts @@ -1,9 +1,13 @@ import * as namespaces from '../../utils/namespaces'; import getStaticAttributeValue from '../../utils/getStaticAttributeValue'; +import fuzzymatch from '../utils/fuzzymatch'; import validateEventHandler from './validateEventHandler'; import { Validator } from '../index'; import { Node } from '../../interfaces'; +const ariaAttributes = 'activedescendant atomic autocomplete busy checked controls describedby disabled dropeffect expanded flowto grabbed haspopup hidden invalid label labelledby level live multiline multiselectable orientation owns posinset pressed readonly relevant required selected setsize sort valuemax valuemin valuenow valuetext'.split(' '); +const ariaSet = new Set(ariaAttributes); + export default function a11y( validator: Validator, node: Node, @@ -18,6 +22,17 @@ export default function a11y( const attributeMap = new Map(); node.attributes.forEach((attribute: Node) => { + if (attribute.name.startsWith('aria-')) { + const name = attribute.name.slice(5); + if (!ariaSet.has(name)) { + const match = fuzzymatch(name, ariaAttributes); + let message = `A11y: Unknown aria attribute 'aria-${name}'`; + if (match) message += ` (did you mean '${match}'?)`; + + validator.warn(message, attribute.start); + } + } + attributeMap.set(attribute.name, attribute); }); @@ -28,13 +43,8 @@ export default function a11y( attributes.slice(0, -1).join(', ') + ` or ${attributes[attributes.length - 1]}` : attributes[0]; - console.log(`warning about ${name}: ${sequence}`) validator.warn(`A11y: <${name}> element should have ${article} ${sequence} attribute`, node.start); } - - else { - console.log('ok', node.name); - } } if (node.name === 'a') { diff --git a/test/validator/samples/a11y-aria-props/input.html b/test/validator/samples/a11y-aria-props/input.html new file mode 100644 index 0000000000..21c6327960 --- /dev/null +++ b/test/validator/samples/a11y-aria-props/input.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/validator/samples/a11y-aria-props/warnings.json b/test/validator/samples/a11y-aria-props/warnings.json new file mode 100644 index 0000000000..5c0ce2c49e --- /dev/null +++ b/test/validator/samples/a11y-aria-props/warnings.json @@ -0,0 +1,19 @@ +[ + { + "message": "A11y: Unknown aria attribute 'aria-labeledby' (did you mean 'labelledby'?)", + "loc": { + "line": 1, + "column": 20 + }, + "pos": 20 + }, + + { + "message": "A11y: element should have an alt, aria-label or aria-labelledby attribute", + "loc": { + "column": 0, + "line": 1 + }, + "pos": 0 + } +]