no-interactive-element-to-noninteractive-role.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
  4. var _ariaQuery = require("aria-query");
  5. var _jsxAstUtils = require("jsx-ast-utils");
  6. var _arrayIncludes = _interopRequireDefault(require("array-includes"));
  7. var _has = _interopRequireDefault(require("has"));
  8. var _isInteractiveElement = _interopRequireDefault(require("../util/isInteractiveElement"));
  9. var _isNonInteractiveRole = _interopRequireDefault(require("../util/isNonInteractiveRole"));
  10. var _isPresentationRole = _interopRequireDefault(require("../util/isPresentationRole"));
  11. /**
  12. * @fileoverview Disallow inherently interactive elements to be assigned
  13. * non-interactive roles.
  14. * @author Jesse Beach
  15. *
  16. */
  17. // ----------------------------------------------------------------------------
  18. // Rule Definition
  19. // ----------------------------------------------------------------------------
  20. var errorMessage = 'Interactive elements should not be assigned non-interactive roles.';
  21. var domElements = (0, _toConsumableArray2["default"])(_ariaQuery.dom.keys());
  22. module.exports = {
  23. meta: {
  24. docs: {
  25. url: 'https://github.com/evcohen/eslint-plugin-jsx-a11y/tree/master/docs/rules/no-interactive-element-to-noninteractive-role.md'
  26. },
  27. schema: [{
  28. type: 'object',
  29. additionalProperties: {
  30. type: 'array',
  31. items: {
  32. type: 'string'
  33. },
  34. uniqueItems: true
  35. }
  36. }]
  37. },
  38. create: function create(context) {
  39. var options = context.options;
  40. return {
  41. JSXAttribute: function JSXAttribute(attribute) {
  42. var attributeName = (0, _jsxAstUtils.propName)(attribute); // $FlowFixMe: [TODO] Mark propName as a JSXIdentifier, not a string.
  43. if (attributeName !== 'role') {
  44. return;
  45. }
  46. var node = attribute.parent;
  47. var attributes = node.attributes;
  48. var type = (0, _jsxAstUtils.elementType)(node);
  49. var role = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'role'));
  50. if (!(0, _arrayIncludes["default"])(domElements, type)) {
  51. // Do not test higher level JSX components, as we do not know what
  52. // low-level DOM element this maps to.
  53. return;
  54. } // Allow overrides from rule configuration for specific elements and
  55. // roles.
  56. var allowedRoles = options[0] || {};
  57. if ((0, _has["default"])(allowedRoles, type) && (0, _arrayIncludes["default"])(allowedRoles[type], role)) {
  58. return;
  59. }
  60. if ((0, _isInteractiveElement["default"])(type, attributes) && ((0, _isNonInteractiveRole["default"])(type, attributes) || (0, _isPresentationRole["default"])(type, attributes))) {
  61. // Visible, non-interactive elements should not have an interactive handler.
  62. context.report({
  63. node: attribute,
  64. message: errorMessage
  65. });
  66. }
  67. }
  68. };
  69. }
  70. };