media-has-caption.js 2.9 KB

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