pull/815/head
Rich Harris 7 years ago
parent 6133976fec
commit a90e072086

@ -1,7 +1,7 @@
import Block from './Block';
import { trimStart, trimEnd } from '../../utils/trim';
import { assign } from '../../shared/index.js';
import getStaticAttributeValue from '../shared/getStaticAttributeValue';
import getStaticAttributeValue from '../../utils/getStaticAttributeValue';
import { DomGenerator } from './index';
import { Node } from '../../interfaces';
import { State } from './interfaces';

@ -3,7 +3,7 @@ import deindent from '../../../../utils/deindent';
import visitStyleAttribute, { optimizeStyle } from './StyleAttribute';
import { stringify } from '../../../../utils/stringify';
import getExpressionPrecedence from '../../../../utils/getExpressionPrecedence';
import getStaticAttributeValue from '../../../shared/getStaticAttributeValue';
import getStaticAttributeValue from '../../../../utils/getStaticAttributeValue';
import { DomGenerator } from '../../index';
import Block from '../../Block';
import { Node } from '../../../../interfaces';

@ -1,6 +1,6 @@
import deindent from '../../../../utils/deindent';
import flattenReference from '../../../../utils/flattenReference';
import getStaticAttributeValue from '../../../shared/getStaticAttributeValue';
import getStaticAttributeValue from '../../../../utils/getStaticAttributeValue';
import { DomGenerator } from '../../index';
import Block from '../../Block';
import { Node } from '../../../../interfaces';

@ -8,7 +8,7 @@ import visitEventHandler from './EventHandler';
import visitBinding from './Binding';
import visitRef from './Ref';
import * as namespaces from '../../../../utils/namespaces';
import getStaticAttributeValue from '../../../shared/getStaticAttributeValue';
import getStaticAttributeValue from '../../../../utils/getStaticAttributeValue';
import addTransitions from './addTransitions';
import { DomGenerator } from '../../index';
import Block from '../../Block';

@ -2,7 +2,7 @@ import attributeLookup from './lookup';
import deindent from '../../../../utils/deindent';
import { stringify } from '../../../../utils/stringify';
import getExpressionPrecedence from '../../../../utils/getExpressionPrecedence';
import getStaticAttributeValue from '../../../shared/getStaticAttributeValue';
import getStaticAttributeValue from '../../../../utils/getStaticAttributeValue';
import { DomGenerator } from '../../index';
import Block from '../../Block';
import { Node } from '../../../../interfaces';

@ -2,7 +2,7 @@ import { DomGenerator } from '../index';
import deindent from '../../../utils/deindent';
import visit from '../visit';
import Block from '../Block';
import getStaticAttributeValue from '../../shared/getStaticAttributeValue';
import getStaticAttributeValue from '../../../utils/getStaticAttributeValue';
import { Node } from '../../../interfaces';
import { State } from '../interfaces';

@ -1,15 +0,0 @@
import { Node } from '../../interfaces';
export default function getStaticAttributeValue(node: Node, name: string) {
const attribute = node.attributes.find(
(attr: Node) => attr.name.toLowerCase() === name
);
if (!attribute) return null;
if (attribute.value.length !== 1 || attribute.value[0].type !== 'Text') {
// TODO catch this in validation phase, give a more useful error (with location etc)
throw new Error(`'${name}' must be a static attribute`);
}
return attribute.value[0].data;
}

@ -0,0 +1,17 @@
import { Node } from '../interfaces';
export default function getStaticAttributeValue(node: Node, name: string) {
const attribute = node.attributes.find(
(attr: Node) => attr.name.toLowerCase() === name
);
if (!attribute) return null;
if (attribute.value.length === 0) return '';
if (attribute.value.length === 1 && attribute.value[0].type === 'Text') {
return attribute.value[0].data;
}
return null;
}

@ -1,4 +1,5 @@
import * as namespaces from '../../utils/namespaces';
import getStaticAttributeValue from '../../utils/getStaticAttributeValue';
import validateEventHandler from './validateEventHandler';
import { Validator } from '../index';
import { Node } from '../../interfaces';
@ -20,11 +21,27 @@ export default function a11y(
attributeMap.set(attribute.name, attribute);
});
function shouldHaveOneOf(attributes: string[], name = node.name) {
if (attributes.length === 0 || !attributes.some((name: string) => attributeMap.has(name))) {
const article = /^[aeiou]/.test(attributes[0]) ? 'an' : 'a';
const sequence = attributes.length > 1 ?
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') {
// anchor-is-valid
const href = attributeMap.get('href');
if (href) {
const value = getValue(href);
if (attributeMap.has('href')) {
const value = getStaticAttributeValue(node, 'href');
if (value === '' || value === '#') {
validator.warn(`A11y: '${value}' is not a valid href attribute`, href.start);
}
@ -33,13 +50,16 @@ export default function a11y(
}
// anchor-has-content
if (!node.children.length) {
if (node.children.length === 0) {
validator.warn(`A11y: <a> element should have child content`, node.start);
}
}
if (node.name === 'img' && !attributeMap.has('alt')) {
validator.warn(`A11y: <img> element should have an alt attribute`, node.start);
if (node.name === 'img') shouldHaveOneOf(['alt']);
if (node.name === 'area') shouldHaveOneOf(['alt', 'aria-label', 'aria-labelledby']);
if (node.name === 'object') shouldHaveOneOf(['title', 'aria-label', 'aria-labelledby']);
if (node.name === 'input' && getStaticAttributeValue(node, 'type') === 'image') {
shouldHaveOneOf(['alt', 'aria-label', 'aria-labelledby'], 'input type="image"');
}
if (node.name === 'figcaption') {

Loading…
Cancel
Save