media-has-caption.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports["default"] = void 0;
  7. var _jsxAstUtils = require("jsx-ast-utils");
  8. var _schemas = require("../util/schemas");
  9. var _getElementType = _interopRequireDefault(require("../util/getElementType"));
  10. /**
  11. * @fileoverview <audio> and <video> elements must have a <track> for captions.
  12. * @author Ethan Cohen
  13. *
  14. */
  15. // ----------------------------------------------------------------------------
  16. // Rule Definition
  17. // ----------------------------------------------------------------------------
  18. var errorMessage = 'Media elements such as <audio> and <video> must have a <track> for captions.';
  19. var MEDIA_TYPES = ['audio', 'video'];
  20. var schema = (0, _schemas.generateObjSchema)({
  21. audio: _schemas.arraySchema,
  22. video: _schemas.arraySchema,
  23. track: _schemas.arraySchema
  24. });
  25. var isMediaType = function isMediaType(context, type) {
  26. var options = context.options[0] || {};
  27. return MEDIA_TYPES.map(function (mediaType) {
  28. return options[mediaType];
  29. }).reduce(function (types, customComponent) {
  30. return types.concat(customComponent);
  31. }, MEDIA_TYPES).some(function (typeToCheck) {
  32. return typeToCheck === type;
  33. });
  34. };
  35. var isTrackType = function isTrackType(context, type) {
  36. var options = context.options[0] || {};
  37. return ['track'].concat(options.track || []).some(function (typeToCheck) {
  38. return typeToCheck === type;
  39. });
  40. };
  41. var _default = {
  42. meta: {
  43. docs: {
  44. url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/media-has-caption.md',
  45. description: 'Enforces that `<audio>` and `<video>` elements must have a `<track>` for captions.'
  46. },
  47. schema: [schema]
  48. },
  49. create: function create(context) {
  50. var elementType = (0, _getElementType["default"])(context);
  51. return {
  52. JSXElement: function JSXElement(node) {
  53. var element = node.openingElement;
  54. var type = elementType(element);
  55. if (!isMediaType(context, type)) {
  56. return;
  57. }
  58. var mutedProp = (0, _jsxAstUtils.getProp)(element.attributes, 'muted');
  59. var mutedPropVal = (0, _jsxAstUtils.getLiteralPropValue)(mutedProp);
  60. if (mutedPropVal === true) {
  61. return;
  62. } // $FlowFixMe https://github.com/facebook/flow/issues/1414
  63. var trackChildren = node.children.filter(function (child) {
  64. if (child.type !== 'JSXElement') {
  65. return false;
  66. } // $FlowFixMe https://github.com/facebook/flow/issues/1414
  67. return isTrackType(context, elementType(child.openingElement));
  68. });
  69. if (trackChildren.length === 0) {
  70. context.report({
  71. node: element,
  72. message: errorMessage
  73. });
  74. return;
  75. }
  76. var hasCaption = trackChildren.some(function (track) {
  77. var kindProp = (0, _jsxAstUtils.getProp)(track.openingElement.attributes, 'kind');
  78. var kindPropValue = (0, _jsxAstUtils.getLiteralPropValue)(kindProp) || '';
  79. return kindPropValue.toLowerCase() === 'captions';
  80. });
  81. if (!hasCaption) {
  82. context.report({
  83. node: element,
  84. message: errorMessage
  85. });
  86. }
  87. }
  88. };
  89. }
  90. };
  91. exports["default"] = _default;
  92. module.exports = exports.default;