function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var literalChildValue = node.parent.children.find(function (child) {
return child.type === 'Literal';
});
if (literalChildValue && (0, _emojiRegex2.default)().test(literalChildValue.value)) {
var rolePropValue = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'role'));
var ariaLabelProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-label');
var arialLabelledByProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-labelledby');
var hasLabel = ariaLabelProp !== undefined || arialLabelledByProp !== undefined;
var isSpan = (0, _jsxAstUtils.elementType)(node) === 'span';
if (hasLabel === false || rolePropValue !== 'img' || isSpan === false) {
context.report({
node: node,
message: errorMessage
});
}
}
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var options = context.options[0] || {};
var componentOptions = options.components || [];
var typeCheck = ['a'].concat(componentOptions);
var nodeType = (0, _jsxAstUtils.elementType)(node);
// Only check anchor elements and custom types.
if (typeCheck.indexOf(nodeType) === -1) {
return;
}
var isAccessible = node.parent.children.some(determineChildType) || (0, _jsxAstUtils.hasAnyProp)(node.attributes, ['dangerouslySetInnerHTML
', 'children']);
if (isAccessible) {
return;
}
context.report({
node: node,
message: errorMessage
});
}
};
}n/a
function determineChildType(child) {
switch (child.type) {
case 'Literal':
return Boolean(child.value);
case 'JSXElement':
return !(0, _isHiddenFromScreenReader2.default)((0, _jsxAstUtils.elementType)(child.openingElement), child.openingElement.
attributes);
case 'JSXExpressionContainer':
if (child.expression.type === 'Identifier') {
return child.expression.name !== 'undefined';
}
return true;
default:
return false;
}
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var attributes = node.attributes;
if ((0, _jsxAstUtils.getProp)(attributes, 'aria-activedescendant') === undefined) {
return;
}
var type = (0, _jsxAstUtils.elementType)(node);
// Do not test higher level JSX components, as we do not know what
// low-level DOM element this maps to.
if (domElements.indexOf(type) === -1) {
return;
}
var tabIndex = (0, _getTabIndex2.default)((0, _jsxAstUtils.getProp)(attributes, 'tabIndex'));
// If this is an interactive element, tabIndex must be either left
// unspecified allowing the inherent tabIndex to obtain or it must be
// zero (allowing for positive, even though that is not ideal). It cannot
// be given a negative value.
if ((0, _isInteractiveElement2.default)(type, attributes) && (tabIndex === undefined || tabIndex >= 0)) {
return;
}
if (tabIndex >= 0) {
return;
}
context.report({
node: node,
message: errorMessage
});
}
};
}n/a
function create(context) {
return {
JSXAttribute: function JSXAttribute(attribute) {
var name = (0, _jsxAstUtils.propName)(attribute);
var normalizedName = name ? name.toLowerCase() : '';
// `aria` needs to be prefix of property.
if (normalizedName.indexOf('aria-') !== 0) {
return;
}
var isValid = ariaAttributes.indexOf(normalizedName) > -1;
if (isValid === false) {
context.report({
node: attribute,
message: errorMessage(name)
});
}
}
};
}n/a
function create(context) {
return {
JSXAttribute: function JSXAttribute(attribute) {
var name = (0, _jsxAstUtils.propName)(attribute);
var normalizedName = name ? name.toLowerCase() : '';
// Not a valid aria-* state or property.
if (normalizedName.indexOf('aria-') !== 0 || _ariaQuery.aria.get(normalizedName) === undefined) {
return;
}
var value = (0, _jsxAstUtils.getLiteralPropValue)(attribute);
// We only want to check literal prop values, so just pass if it's null.
if (value === null) {
return;
}
// These are the attributes of the property/state to check against.
var attributes = _ariaQuery.aria.get(normalizedName);
var permittedType = attributes.type;
var allowUndefined = attributes.allowUndefined || false;
var permittedValues = attributes.values || [];
var isValid = validityCheck(value, permittedType, permittedValues) || allowUndefined && value === undefined;
if (isValid) {
return;
}
context.report({
node: attribute,
message: errorMessage(name, permittedType, permittedValues)
});
}
};
}n/a
function validityCheck(value, expectedType, permittedValues) {
switch (expectedType) {
case 'boolean':
return typeof value === 'boolean';
case 'string':
return typeof value === 'string';
case 'tristate':
return typeof value === 'boolean' || value === 'mixed';
case 'integer':
case 'number':
// Booleans resolve to 0/1 values so hard check that it's not first.
return typeof value !== 'boolean' && isNaN(Number(value)) === false;
case 'token':
return permittedValues.indexOf(typeof value === 'string' ? value.toLowerCase() : value) > -1;
case 'tokenlist':
return typeof value === 'string' && value.split(' ').every(function (token) {
return permittedValues.indexOf(token.toLowerCase()) > -1;
});
default:
return false;
}
}n/a
function create(context) {
return {
JSXAttribute: function JSXAttribute(attribute) {
// Determine if ignoreNonDOM is set to true
// If true, then do not run rule.
var options = context.options[0] || {};
var ignoreNonDOM = !!options.ignoreNonDOM;
if (ignoreNonDOM) {
var type = (0, _jsxAstUtils.elementType)(attribute.parent);
if (!_ariaQuery.dom.get(type)) {
return;
}
}
// Get prop name
var name = (0, _jsxAstUtils.propName)(attribute);
var normalizedName = name ? name.toUpperCase() : '';
if (normalizedName !== 'ROLE') {
return;
}
var value = (0, _jsxAstUtils.getLiteralPropValue)(attribute);
// If value is undefined, then the role attribute will be dropped in the DOM.
// If value is null, then getLiteralAttributeValue is telling us that the
// value isn't in the form of a literal.
if (value === undefined || value === null) {
return;
}
var normalizedValues = String(value).toLowerCase().split(' ');
var validRoles = [].concat(_toConsumableArray(_ariaQuery.roles.keys())).filter(function (role) {
return _ariaQuery.roles.get(role).abstract === false;
});
var isValid = normalizedValues.every(function (val) {
return validRoles.indexOf(val) > -1;
});
if (isValid === true) {
return;
}
context.report({
node: attribute,
message: errorMessage
});
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var nodeType = (0, _jsxAstUtils.elementType)(node);
var nodeAttrs = _ariaQuery.dom.get(nodeType) || {};
var _nodeAttrs$reserved = nodeAttrs.reserved,
isReservedNodeType = _nodeAttrs$reserved === undefined ? false : _nodeAttrs$reserved;
// If it's not reserved, then it can have aria-* roles, states, and properties
if (isReservedNodeType === false) {
return;
}
var invalidAttributes = [].concat(_toConsumableArray(_ariaQuery.aria.keys())).concat('role');
node.attributes.forEach(function (prop) {
if (prop.type === 'JSXSpreadAttribute') {
return;
}
var name = (0, _jsxAstUtils.propName)(prop);
var normalizedName = name ? name.toLowerCase() : '';
if (invalidAttributes.indexOf(normalizedName) > -1) {
context.report({
node: node,
message: errorMessage(name)
});
}
});
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var props = node.attributes;
if ((0, _jsxAstUtils.getProp)(props, 'onclick') === undefined) {
return;
}
var type = (0, _jsxAstUtils.elementType)(node);
var requiredProps = ['onkeydown', 'onkeyup', 'onkeypress'];
if ((0, _isHiddenFromScreenReader2.default)(type, props)) {
return;
} else if ((0, _isInteractiveElement2.default)(type, props)) {
return;
} else if ((0, _jsxAstUtils.hasAnyProp)(props, requiredProps)) {
return;
}
// Visible, non-interactive elements with click handlers require one keyboard event listener.
context.report({
node: node,
message: errorMessage
});
}
};
}n/a
function getImplicitRole(type, attributes) {
var normalizedType = type.toUpperCase();
if (_implicitRoles2.default[normalizedType]) {
return _implicitRoles2.default[normalizedType](attributes);
}
return '';
}n/a
function getSuggestion(word) {
var dictionary = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var limit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 2;
var distances = dictionary.reduce(function (suggestions, dictionaryWord) {
var distance = (0, _damerauLevenshtein2.default)(word.toUpperCase(), dictionaryWord.toUpperCase());
var steps = distance.steps;
suggestions[dictionaryWord] = steps; // eslint-disable-line
return suggestions;
}, {});
return Object.keys(distances).filter(function (suggestion) {
return distances[suggestion] <= THRESHOLD;
}).sort(function (a, b) {
return distances[a] - distances[b];
}) // Sort by distance
.slice(0, limit);
}n/a
function getTabIndex(tabIndex) {
var literalValue = (0, _jsxAstUtils.getLiteralPropValue)(tabIndex);
// String and number values.
if (['string', 'number'].indexOf(typeof literalValue === 'undefined' ? 'undefined' : _typeof(literalValue)) > -1) {
// Empty string will convert to zero, so check for it explicity.
if (typeof literalValue === 'string' && literalValue.length === 0) {
return undefined;
}
var value = Number(literalValue);
if (Number.isNaN(value)) {
return undefined;
}
return Number.isInteger(value) ? value : undefined;
}
// Booleans are not valid values, return undefined.
if (literalValue === true || literalValue === false) {
return undefined;
}
return (0, _jsxAstUtils.getPropValue)(tabIndex);
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var typeCheck = headings.concat(context.options[0]);
var nodeType = (0, _jsxAstUtils.elementType)(node);
// Only check 'h*' elements and custom types.
if (typeCheck.indexOf(nodeType) === -1) {
return;
}
var isAccessible = node.parent.children.some(determineChildType) || (0, _jsxAstUtils.hasAnyProp)(node.attributes, ['dangerouslySetInnerHTML
', 'children']);
if (isAccessible) {
return;
}
context.report({
node: node,
message: errorMessage
});
}
};
}n/a
function determineChildType(child) {
switch (child.type) {
case 'Literal':
return Boolean(child.value);
case 'JSXElement':
return !(0, _isHiddenFromScreenReader2.default)((0, _jsxAstUtils.elementType)(child.openingElement), child.openingElement.
attributes);
case 'JSXExpressionContainer':
if (child.expression.type === 'Identifier') {
return child.expression.name !== 'undefined';
}
return true;
default:
return false;
}
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var options = context.options[0] || {};
var componentOptions = options.components || [];
var typesToValidate = ['a'].concat(componentOptions);
var nodeType = (0, _jsxAstUtils.elementType)(node);
// Only check 'a' elements and custom types.
if (typesToValidate.indexOf(nodeType) === -1) {
return;
}
var propOptions = options.specialLink || [];
var propsToValidate = ['href'].concat(propOptions);
var values = propsToValidate.map(function (prop) {
return (0, _jsxAstUtils.getProp)(node.attributes, prop);
}).map(function (prop) {
return (0, _jsxAstUtils.getPropValue)(prop);
});
values.forEach(function (value) {
if (value === '#') {
context.report({
node: node,
message: errorMessage
});
}
});
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var type = (0, _jsxAstUtils.elementType)(node);
if (type && type !== 'html') {
return;
}
var lang = (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'lang'));
if (lang) {
return;
}
context.report({
node: node,
message: errorMessage
});
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var type = (0, _jsxAstUtils.elementType)(node);
if (type && type !== 'iframe') {
return;
}
var title = (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'title'));
if (title && typeof title === 'string') {
return;
}
context.report({
node: node,
message: errorMessage
});
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var options = context.options[0] || {};
var componentOptions = options.components || [];
var typesToValidate = ['img'].concat(componentOptions);
var nodeType = (0, _jsxAstUtils.elementType)(node);
// Only check 'img' elements and custom types.
if (typesToValidate.indexOf(nodeType) === -1) {
return;
}
var roleProp = (0, _jsxAstUtils.getProp)(node.attributes, 'role');
var roleValue = (0, _jsxAstUtils.getPropValue)(roleProp);
var isPresentation = roleProp && typeof roleValue === 'string' && roleValue.toLowerCase() === 'presentation';
var altProp = (0, _jsxAstUtils.getProp)(node.attributes, 'alt');
// Missing alt prop error.
if (altProp === undefined) {
if (isPresentation) {
context.report({
node: node,
message: 'Prefer alt="" over role="presentation". First rule of aria is to not use aria if it can be achieved via native
HTML.'
});
return;
}
context.report({
node: node,
message: nodeType + ' elements must have an alt prop, either with meaningful text, or an empty string for decorative images
.'
});
return;
}
// Check if alt prop is undefined.
var altValue = (0, _jsxAstUtils.getPropValue)(altProp);
var isNullValued = altProp.value === null; // <img alt />
if (altValue && !isNullValued || altValue === '') {
return;
}
// Undefined alt prop error.
context.report({
node: node,
message: 'Invalid alt value for ' + nodeType + '. Use alt="" for presentational images.'
});
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var options = context.options[0] || {};
var componentOptions = options.components || [];
var typesToValidate = ['img'].concat(componentOptions);
var nodeType = (0, _jsxAstUtils.elementType)(node);
// Only check 'label' elements and custom types.
if (typesToValidate.indexOf(nodeType) === -1) {
return;
}
var altProp = (0, _jsxAstUtils.getProp)(node.attributes, 'alt');
// Return if alt prop is not present.
if (altProp === undefined) {
return;
}
var value = (0, _jsxAstUtils.getLiteralPropValue)(altProp);
var isVisible = (0, _isHiddenFromScreenReader2.default)(nodeType, node.attributes) === false;
var _options$words = options.words,
words = _options$words === undefined ? [] : _options$words;
var redundantWords = REDUNDANT_WORDS.concat(words);
if (typeof value === 'string' && isVisible) {
var hasRedundancy = redundantWords.some(function (word) {
return Boolean(value.match(new RegExp('(?!{)\\b' + word + '\\b(?!})', 'i')));
});
if (hasRedundancy === true) {
context.report({
node: node,
message: errorMessage
});
}
}
}
};
}n/a
function isHiddenFromScreenReader(type, attributes) {
if (type.toUpperCase() === 'INPUT') {
var hidden = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(attributes, 'type'));
if (hidden && hidden.toUpperCase() === 'HIDDEN') {
return true;
}
}
var ariaHidden = (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(attributes, 'aria-hidden'));
return ariaHidden === true;
}n/a
function isInteractiveElement(tagName, attributes) {
// Do not test higher level JSX components, as we do not know what
// low-level DOM element this maps to.
if (DOMElements.indexOf(tagName) === -1) {
return true;
}
if ({}.hasOwnProperty.call(interactiveElementsMap, tagName) === false) {
return false;
}
return interactiveElementsMap[tagName](attributes);
}n/a
function isInteractiveRole(tagName, attributes) {
// Do not test higher level JSX components, as we do not know what
// low-level DOM element this maps to.
if ([].concat(_toConsumableArray(_ariaQuery.dom.keys())).indexOf(tagName) === -1) {
return true;
}
var value = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(attributes, 'role'));
// If value is undefined, then the role attribute will be dropped in the DOM.
// If value is null, then getLiteralAttributeValue is telling us that the
// value isn't in the form of a literal
if (value === undefined || value === null) {
return false;
}
var normalizedValues = String(value).toLowerCase().split(' ');
var isInteractive = normalizedValues.every(function (val) {
return VALID_ROLES.indexOf(val) > -1;
});
return isInteractive;
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var options = context.options[0] || {};
var componentOptions = options.components || [];
var typesToValidate = ['label'].concat(componentOptions);
var nodeType = (0, _jsxAstUtils.elementType)(node);
// Only check 'label' elements and custom types.
if (typesToValidate.indexOf(nodeType) === -1) {
return;
}
var htmlForAttr = (0, _jsxAstUtils.getProp)(node.attributes, 'htmlFor');
var htmlForValue = (0, _jsxAstUtils.getPropValue)(htmlForAttr);
var isInvalid = htmlForAttr === false || !htmlForValue;
if (isInvalid) {
context.report({
node: node,
message: errorMessage
});
}
}
};
}n/a
function create(context) {
return {
JSXAttribute: function JSXAttribute(node) {
var name = (0, _jsxAstUtils.propName)(node);
if (name && name.toUpperCase() !== 'LANG') {
return;
}
var parent = node.parent;
var type = (0, _jsxAstUtils.elementType)(parent);
if (type && type !== 'html') {
return;
}
var value = (0, _jsxAstUtils.getLiteralPropValue)(node);
// Don't check identifiers
if (value === null) {
return;
} else if (value === undefined) {
context.report({
node: node,
message: errorMessage
});
return;
}
var hyphen = value.indexOf('-');
var lang = hyphen > -1 ? value.substring(0, hyphen) : value;
var country = hyphen > -1 ? value.substring(3) : undefined;
if (_ISO2.default.languages.indexOf(lang) > -1 && (country === undefined || _ISO2.default.countries.indexOf(country) > -1)) {
return;
}
context.report({
node: node,
message: errorMessage
});
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var attributes = node.attributes;
// Check onmouseover / onfocus pairing.
var onMouseOver = (0, _jsxAstUtils.getProp)(attributes, 'onMouseOver');
var onMouseOverValue = (0, _jsxAstUtils.getPropValue)(onMouseOver);
if (onMouseOver && (onMouseOverValue !== null || onMouseOverValue !== undefined)) {
var hasOnFocus = (0, _jsxAstUtils.getProp)(attributes, 'onFocus');
var onFocusValue = (0, _jsxAstUtils.getPropValue)(hasOnFocus);
if (hasOnFocus === false || onFocusValue === null || onFocusValue === undefined) {
context.report({
node: node,
message: mouseOverErrorMessage
});
}
}
// Checkout onmouseout / onblur pairing
var onMouseOut = (0, _jsxAstUtils.getProp)(attributes, 'onMouseOut');
var onMouseOutValue = (0, _jsxAstUtils.getPropValue)(onMouseOut);
if (onMouseOut && (onMouseOutValue !== null || onMouseOutValue !== undefined)) {
var hasOnBlur = (0, _jsxAstUtils.getProp)(attributes, 'onBlur');
var onBlurValue = (0, _jsxAstUtils.getPropValue)(hasOnBlur);
if (hasOnBlur === false || onBlurValue === null || onBlurValue === undefined) {
context.report({
node: node,
message: mouseOutErrorMessage
});
}
}
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var accessKey = (0, _jsxAstUtils.getProp)(node.attributes, 'accesskey');
var accessKeyValue = (0, _jsxAstUtils.getPropValue)(accessKey);
if (accessKey && accessKeyValue) {
context.report({
node: node,
message: errorMessage
});
}
}
};
}n/a
function create(context) {
return {
JSXAttribute: function JSXAttribute(attribute) {
// Don't normalize, since React only recognizes autoFocus on low-level DOM elements.
if ((0, _jsxAstUtils.propName)(attribute) === 'autoFocus') {
context.report({
node: attribute,
message: errorMessage
});
}
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var options = context.options[0] || {};
var elementOptions = options.elements || DEFAULT_ELEMENTS;
var type = (0, _jsxAstUtils.elementType)(node);
var distractingElement = elementOptions.find(function (element) {
return type === element;
});
if (distractingElement) {
context.report({
node: node,
message: errorMessage(distractingElement)
});
}
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var nodeType = (0, _jsxAstUtils.elementType)(node);
if (applicableTypes.indexOf(nodeType) === -1) {
return;
}
var onChange = (0, _jsxAstUtils.getProp)(node.attributes, 'onChange');
var hasOnBlur = (0, _jsxAstUtils.getProp)(node.attributes, 'onBlur') !== undefined;
if (onChange && !hasOnBlur) {
context.report({
node: node,
message: errorMessage
});
}
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var type = (0, _jsxAstUtils.elementType)(node);
var implicitRole = (0, _getImplicitRole2.default)(type, node.attributes);
if (implicitRole === '') {
return;
}
var role = (0, _jsxAstUtils.getProp)(node.attributes, 'role');
var roleValue = (0, _jsxAstUtils.getLiteralPropValue)(role);
if (typeof roleValue === 'string' && roleValue.toUpperCase() === implicitRole.toUpperCase()) {
context.report({
node: node,
message: errorMessage(type, implicitRole.toLowerCase())
});
}
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var props = node.attributes;
var type = (0, _jsxAstUtils.elementType)(node);
var interactiveProps = ['onclick', 'ondblclick', 'onkeydown', 'onkeyup', 'onkeypress'];
if ((0, _isHiddenFromScreenReader2.default)(type, props)) {
return;
} else if ((0, _isInteractiveElement2.default)(type, props)) {
return;
} else if ((0, _jsxAstUtils.hasAnyProp)(props, interactiveProps) === false) {
return;
}
// Visible, non-interactive elements should not have an interactive handler.
context.report({
node: node,
message: errorMessage
});
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var attributes = node.attributes;
if ((0, _jsxAstUtils.getProp)(attributes, 'onClick') === undefined) {
return;
}
var type = (0, _jsxAstUtils.elementType)(node);
if ((0, _isHiddenFromScreenReader2.default)(type, attributes)) {
return;
} else if ((0, _isInteractiveElement2.default)(type, attributes)) {
return;
} else if (!(0, _isInteractiveRole2.default)(type, attributes)) {
// A non-interactive element or an element without an interactive
// role might have a click hanlder attached to it in order to catch
// bubbled click events. In this case, the author should apply a role
// of presentation to the element to indicate that it is not meant to
// be interactive.
return;
} else if ((0, _getTabIndex2.default)((0, _jsxAstUtils.getProp)(attributes, 'tabIndex')) !== undefined) {
return;
}
context.report({
node: node,
message: errorMessage
});
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var attributes = node.attributes;
if ((0, _jsxAstUtils.getProp)(attributes, 'onclick') === undefined) {
return;
}
var type = (0, _jsxAstUtils.elementType)(node);
if ((0, _isHiddenFromScreenReader2.default)(type, attributes)) {
return;
} else if ((0, _isInteractiveElement2.default)(type, attributes)) {
return;
} else if ((0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(attributes, 'role'))) {
return;
}
// Visible, non-interactive elements require role attribute.
context.report({
node: node,
message: errorMessage
});
}
};
}n/a
function create(context) {
return {
JSXAttribute: function JSXAttribute(attribute) {
var name = (0, _jsxAstUtils.propName)(attribute);
var normalizedName = name ? name.toUpperCase() : '';
if (normalizedName !== 'ROLE') {
return;
}
var value = (0, _jsxAstUtils.getLiteralPropValue)(attribute);
// If value is undefined, then the role attribute will be dropped in the DOM.
// If value is null, then getLiteralAttributeValue is telling us
// that the value isn't in the form of a literal.
if (value === undefined || value === null) {
return;
}
var normalizedValues = String(value).toLowerCase().split(' ');
var validRoles = normalizedValues.filter(function (val) {
return [].concat(_toConsumableArray(_ariaQuery.roles.keys())).indexOf(val) > -1;
});
validRoles.forEach(function (role) {
var _roles$get = _ariaQuery.roles.get(role),
requiredProps = _roles$get.requiredProps;
if (requiredProps.length > 0) {
var hasRequiredProps = requiredProps.every(function (prop) {
return (0, _jsxAstUtils.getProp)(attribute.parent.attributes, prop);
});
if (hasRequiredProps === false) {
context.report({
node: attribute,
message: errorMessage(role.toLowerCase(), requiredProps)
});
}
}
});
}
};
}n/a
function create(context) {
return {
JSXOpeningElement: function JSXOpeningElement(node) {
// If role is not explicitly defined, then try and get its implicit role.
var type = (0, _jsxAstUtils.elementType)(node);
var role = (0, _jsxAstUtils.getProp)(node.attributes, 'role');
var roleValue = role ? (0, _jsxAstUtils.getLiteralPropValue)(role) : (0, _getImplicitRole2.default)(type, node.attributes);
var isImplicit = roleValue && role === undefined;
// If there is no explicit or implicit role, then assume that the element
// can handle the global set of aria-* properties.
// This actually isn't true - should fix in future release.
if (typeof roleValue !== 'string' || _ariaQuery.roles.get(roleValue.toLowerCase()) === undefined) {
return;
}
// Make sure it has no aria-* properties defined outside of its property set.
var propertySet = _ariaQuery.roles.get(roleValue.toLowerCase()).props;
var invalidAriaPropsForRole = [].concat(_toConsumableArray(_ariaQuery.aria.keys())).map(function (attribute) {
return attribute.toLowerCase();
}).filter(function (attribute) {
return propertySet.indexOf(attribute) === -1;
});
node.attributes.forEach(function (prop) {
if (prop.type === 'JSXSpreadAttribute') {
return;
}
var name = (0, _jsxAstUtils.propName)(prop);
var normalizedName = name ? name.toLowerCase() : '';
if (invalidAriaPropsForRole.indexOf(normalizedName) > -1) {
context.report({
node: node,
message: errorMessage(name, roleValue, type, isImplicit)
});
}
});
}
};
}n/a
function enumArraySchema() {
var enumeratedList = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
return (0, _objectAssign2.default)({}, arraySchema, {
items: {
type: 'string',
enum: enumeratedList
}
});
}n/a
function generateObjSchema() {
var properties = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return {
type: 'object',
properties: properties
};
}n/a
function create(context) {
return {
JSXAttribute: function JSXAttribute(node) {
var name = (0, _jsxAstUtils.propName)(node);
if (name && name.toUpperCase() !== 'SCOPE') {
return;
}
var parent = node.parent;
var tagName = (0, _jsxAstUtils.elementType)(parent);
// Do not test higher level JSX components, as we do not know what
// low-level DOM element this maps to.
if ([].concat(_toConsumableArray(_ariaQuery.dom.keys())).indexOf(tagName) === -1) {
return;
} else if (tagName && tagName.toUpperCase() === 'TH') {
return;
}
context.report({
node: node,
message: errorMessage
});
}
};
}n/a
function create(context) {
return {
JSXAttribute: function JSXAttribute(attribute) {
var name = (0, _jsxAstUtils.propName)(attribute);
var normalizedName = name ? name.toUpperCase() : '';
// Check if tabIndex is the attribute
if (normalizedName !== 'TABINDEX') {
return;
}
// Only check literals because we can't infer values from certain expressions.
var value = Number((0, _jsxAstUtils.getLiteralPropValue)(attribute));
if (isNaN(value) || value <= 0) {
return;
}
context.report({
node: attribute,
message: errorMessage
});
}
};
}n/a