pull/1721/head
Rich Harris 7 years ago
parent 8b803b7438
commit 5fa14b371e

@ -250,6 +250,32 @@ export default class Element extends Node {
});
}
if (this.name === 'figcaption') {
if (this.parent.name !== 'figure') {
this.component.warn(this, {
code: `a11y-structure`,
message: `A11y: <figcaption> must be an immediate child of <figure>`
});
}
}
if (this.name === 'figure') {
const children = this.children.filter(node => {
if (node.type === 'Comment') return false;
if (node.type === 'Text') return /\S/.test(node.data);
return true;
});
const index = children.findIndex(child => child.name === 'figcaption');
if (index !== -1 && (index !== 0 && index !== children.length - 1)) {
this.component.warn(children[index], {
code: `a11y-structure`,
message: `A11y: <figcaption> must be first or last child of <figure>`
});
}
}
this.validateAttributes();
this.validateBindings();
this.validateContent();
@ -352,7 +378,7 @@ export default class Element extends Node {
});
}
let ancestor = parent;
let ancestor = this.parent;
do {
if (ancestor.type === 'InlineComponent') break;
if (ancestor.type === 'Element' && /-/.test(ancestor.name)) break;
@ -366,7 +392,7 @@ export default class Element extends Node {
message
});
}
} while (ancestor);
} while (ancestor = ancestor.parent);
if (!ancestor) {
component.error(attribute, {
@ -409,6 +435,17 @@ export default class Element extends Node {
shouldHaveAttribute(this, requiredAttributes);
}
}
if (this.name === 'input') {
const type = attributeMap.get('type');
if (type && type.getStaticValue() === 'image') {
shouldHaveAttribute(
this,
['alt', 'aria-label', 'aria-labelledby'],
'input type="image"'
);
}
}
}
}

@ -37,10 +37,6 @@ export default function a11y(
}
}
if (node.name === 'input' && getStaticAttributeValue(node, 'type') === 'image') {
shouldHaveAttribute(['alt', 'aria-label', 'aria-labelledby'], 'input type="image"');
}
if (/^h[1-6]$/.test(node.name)) {
if (attributeMap.has('aria-hidden')) {
validator.warn(attributeMap.get('aria-hidden'), {

@ -1,59 +0,0 @@
import * as namespaces from '../../utils/namespaces';
import validateEventHandler from './validateEventHandler';
import { Node } from '../../interfaces';
import { dimensions } from '../../utils/patterns';
import isVoidElementName from '../../utils/isVoidElementName';
import isValidIdentifier from '../../utils/isValidIdentifier';
import Component from '../../compile/Component';
const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/;
export default function validateElement(
component: Component,
node: Node,
refs: Map<string, Node[]>,
refCallees: Node[],
stack: Node[],
elementStack: Node[]
) {
node.attributes.forEach((attribute: Node) => {
if (attribute.type === 'Attribute') {
if (attribute.name === 'value' && node.name === 'textarea') {
if (node.children.length) {
component.error(attribute, {
code: `textarea-duplicate-value`,
message: `A <textarea> can have either a value attribute or (equivalently) child content, but not both`
});
}
}
}
});
}
function checkTypeAttribute(component: Component, node: Node) {
const attribute = node.attributes.find(
(attribute: Node) => attribute.name === 'type'
);
if (!attribute) return null;
if (attribute.value === true) {
component.error(attribute, {
code: `missing-type`,
message: `'type' attribute must be specified`
});
}
if (isDynamic(attribute)) {
component.error(attribute, {
code: `invalid-type`,
message: `'type' attribute cannot be dynamic if input uses two-way binding`
});
}
return attribute.value[0].data;
}
function isDynamic(attribute: Node) {
if (attribute.value === true) return false;
return attribute.value.length > 1 || attribute.value[0].type !== 'Text';
}
Loading…
Cancel
Save