You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mayHaveAccessibleLabel.js 4.4 KiB

3 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. 'use strict';
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = mayHaveAccessibleLabel;
  6. var _arrayIncludes = require('array-includes');
  7. var _arrayIncludes2 = _interopRequireDefault(_arrayIncludes);
  8. var _jsxAstUtils = require('jsx-ast-utils');
  9. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  10. function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } /**
  11. * Returns true if a labelling element is found or if it cannot determine if
  12. * a label is present because of expression containers or spread attributes.
  13. * A false return value means that the node definitely does not have a label,
  14. * but a true return return value means that the node may or may not have a
  15. * label.
  16. *
  17. *
  18. */
  19. function hasLabellingProp(openingElement) {
  20. var additionalLabellingProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  21. var labellingProps = ['alt', // Assume alt is used correctly on an image
  22. 'aria-label', 'aria-labelledby'].concat(_toConsumableArray(additionalLabellingProps));
  23. return openingElement.attributes.some(function (attribute) {
  24. // We must assume that a spread value contains a labelling prop.
  25. if (attribute.type !== 'JSXAttribute') {
  26. return true;
  27. }
  28. // Attribute matches.
  29. if ((0, _arrayIncludes2.default)(labellingProps, (0, _jsxAstUtils.propName)(attribute)) && !!(0, _jsxAstUtils.getPropValue)(attribute)) {
  30. return true;
  31. }
  32. return false;
  33. });
  34. }
  35. function mayHaveAccessibleLabel(root) {
  36. var maxDepth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
  37. var additionalLabellingProps = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
  38. function checkElement(node, depth) {
  39. // Bail when maxDepth is exceeded.
  40. if (depth > maxDepth) {
  41. return false;
  42. }
  43. // Check for literal text.
  44. if (node.type === 'Literal' && !!node.value) {
  45. return true;
  46. }
  47. // Assume an expression container renders a label. It is the best we can
  48. // do in this case.
  49. if (node.type === 'JSXExpressionContainer') {
  50. return true;
  51. }
  52. // Check for JSXText.
  53. // $FlowFixMe Remove after updating ast-types-flow
  54. if (node.type === 'JSXText' && !!node.value) {
  55. return true;
  56. }
  57. // Check for labelling props.
  58. if (node.openingElement
  59. /* $FlowFixMe */
  60. && hasLabellingProp(node.openingElement, additionalLabellingProps)) {
  61. return true;
  62. }
  63. // Recurse into the child element nodes.
  64. if (node.children) {
  65. /* $FlowFixMe */
  66. for (var i = 0; i < node.children.length; i += 1) {
  67. /* $FlowFixMe */
  68. if (checkElement(node.children[i], depth + 1)) {
  69. return true;
  70. }
  71. }
  72. }
  73. return false;
  74. }
  75. return checkElement(root, 0);
  76. }