@arcaauth/eslint-plugin-jsx-a11y 6.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/.babelrc +17 -0
  2. package/.eslintrc +44 -0
  3. package/CHANGELOG.md +774 -0
  4. package/LICENSE.md +8 -0
  5. package/README.md +423 -0
  6. package/__mocks__/IdentifierMock.js +15 -0
  7. package/__mocks__/JSXAttributeMock.js +39 -0
  8. package/__mocks__/JSXElementMock.js +37 -0
  9. package/__mocks__/JSXExpressionContainerMock.js +15 -0
  10. package/__mocks__/JSXSpreadAttributeMock.js +18 -0
  11. package/__mocks__/JSXTextMock.js +17 -0
  12. package/__mocks__/LiteralMock.js +17 -0
  13. package/__mocks__/genInteractives.js +218 -0
  14. package/__tests__/__util__/axeMapping.js +6 -0
  15. package/__tests__/__util__/helpers/getESLintCoreRule.js +9 -0
  16. package/__tests__/__util__/helpers/parsers.js +186 -0
  17. package/__tests__/__util__/parserOptionsMapper.js +53 -0
  18. package/__tests__/__util__/ruleOptionsMapperFactory.js +33 -0
  19. package/__tests__/index-test.js +40 -0
  20. package/__tests__/src/rules/accessible-emoji-test.js +66 -0
  21. package/__tests__/src/rules/alt-text-test.js +291 -0
  22. package/__tests__/src/rules/anchor-ambiguous-text-test.js +117 -0
  23. package/__tests__/src/rules/anchor-has-content-test.js +54 -0
  24. package/__tests__/src/rules/anchor-is-valid-test.js +532 -0
  25. package/__tests__/src/rules/aria-activedescendant-has-tabindex-test.js +95 -0
  26. package/__tests__/src/rules/aria-props-test.js +69 -0
  27. package/__tests__/src/rules/aria-proptypes-test.js +311 -0
  28. package/__tests__/src/rules/aria-role-test.js +118 -0
  29. package/__tests__/src/rules/aria-unsupported-elements-test.js +75 -0
  30. package/__tests__/src/rules/autocomplete-valid-test.js +77 -0
  31. package/__tests__/src/rules/click-events-have-key-events-test.js +77 -0
  32. package/__tests__/src/rules/control-has-associated-label-test.js +327 -0
  33. package/__tests__/src/rules/heading-has-content-test.js +85 -0
  34. package/__tests__/src/rules/html-has-lang-test.js +42 -0
  35. package/__tests__/src/rules/iframe-has-title-test.js +55 -0
  36. package/__tests__/src/rules/img-redundant-alt-test.js +137 -0
  37. package/__tests__/src/rules/interactive-supports-focus-test.js +267 -0
  38. package/__tests__/src/rules/label-has-associated-control-test.js +243 -0
  39. package/__tests__/src/rules/label-has-for-test.js +235 -0
  40. package/__tests__/src/rules/lang-test.js +59 -0
  41. package/__tests__/src/rules/media-has-caption-test.js +220 -0
  42. package/__tests__/src/rules/mouse-events-have-key-events-test.js +154 -0
  43. package/__tests__/src/rules/no-access-key-test.js +48 -0
  44. package/__tests__/src/rules/no-aria-hidden-on-focusable-test.js +44 -0
  45. package/__tests__/src/rules/no-autofocus-test.js +68 -0
  46. package/__tests__/src/rules/no-distracting-elements-test.js +51 -0
  47. package/__tests__/src/rules/no-interactive-element-to-noninteractive-role-test.js +405 -0
  48. package/__tests__/src/rules/no-noninteractive-element-interactions-test.js +502 -0
  49. package/__tests__/src/rules/no-noninteractive-element-to-interactive-role-test.js +500 -0
  50. package/__tests__/src/rules/no-noninteractive-tabindex-test.js +123 -0
  51. package/__tests__/src/rules/no-onchange-test.js +57 -0
  52. package/__tests__/src/rules/no-redundant-roles-test.js +98 -0
  53. package/__tests__/src/rules/no-static-element-interactions-test.js +501 -0
  54. package/__tests__/src/rules/prefer-tag-over-role-test.js +63 -0
  55. package/__tests__/src/rules/role-has-required-aria-props-test.js +134 -0
  56. package/__tests__/src/rules/role-supports-aria-props-test.js +570 -0
  57. package/__tests__/src/rules/scope-test.js +50 -0
  58. package/__tests__/src/rules/tabindex-no-positive-test.js +55 -0
  59. package/__tests__/src/util/attributesComparator-test.js +91 -0
  60. package/__tests__/src/util/getAccessibleChildText-test.js +174 -0
  61. package/__tests__/src/util/getComputedRole-test.js +71 -0
  62. package/__tests__/src/util/getElementType-test.js +154 -0
  63. package/__tests__/src/util/getExplicitRole-test.js +35 -0
  64. package/__tests__/src/util/getImplicitRole-test.js +25 -0
  65. package/__tests__/src/util/getSuggestion-test.js +33 -0
  66. package/__tests__/src/util/getTabIndex-test.js +85 -0
  67. package/__tests__/src/util/hasAccessibleChild-test.js +157 -0
  68. package/__tests__/src/util/implicitRoles/input-test.js +87 -0
  69. package/__tests__/src/util/implicitRoles/menu-test.js +20 -0
  70. package/__tests__/src/util/implicitRoles/menuitem-test.js +38 -0
  71. package/__tests__/src/util/isAbstractRole-test.js +51 -0
  72. package/__tests__/src/util/isContentEditable-test.js +52 -0
  73. package/__tests__/src/util/isDOMElement-test.js +30 -0
  74. package/__tests__/src/util/isDisabledElement-test.js +88 -0
  75. package/__tests__/src/util/isFocusable-test.js +111 -0
  76. package/__tests__/src/util/isInteractiveElement-test.js +104 -0
  77. package/__tests__/src/util/isInteractiveRole-test.js +59 -0
  78. package/__tests__/src/util/isNonInteractiveElement-test.js +97 -0
  79. package/__tests__/src/util/isNonInteractiveRole-test.js +59 -0
  80. package/__tests__/src/util/isNonLiteralProperty-test.js +52 -0
  81. package/__tests__/src/util/isSemanticRoleElement-test.js +72 -0
  82. package/__tests__/src/util/mayContainChildComponent-test.js +219 -0
  83. package/__tests__/src/util/mayHaveAccessibleLabel-test.js +256 -0
  84. package/__tests__/src/util/parserOptionsMapper-test.js +93 -0
  85. package/__tests__/src/util/schemas-test.js +35 -0
  86. package/docs/rules/accessible-emoji.md +30 -0
  87. package/docs/rules/alt-text.md +168 -0
  88. package/docs/rules/anchor-ambiguous-text.md +91 -0
  89. package/docs/rules/anchor-has-content.md +64 -0
  90. package/docs/rules/anchor-is-valid.md +270 -0
  91. package/docs/rules/aria-activedescendant-has-tabindex.md +52 -0
  92. package/docs/rules/aria-props.md +29 -0
  93. package/docs/rules/aria-proptypes.md +30 -0
  94. package/docs/rules/aria-role.md +51 -0
  95. package/docs/rules/aria-unsupported-elements.md +30 -0
  96. package/docs/rules/autocomplete-valid.md +49 -0
  97. package/docs/rules/click-events-have-key-events.md +28 -0
  98. package/docs/rules/control-has-associated-label.md +113 -0
  99. package/docs/rules/heading-has-content.md +67 -0
  100. package/docs/rules/html-has-lang.md +31 -0
  101. package/docs/rules/iframe-has-title.md +37 -0
  102. package/docs/rules/img-redundant-alt.md +48 -0
  103. package/docs/rules/interactive-supports-focus.md +156 -0
  104. package/docs/rules/label-has-associated-control.md +152 -0
  105. package/docs/rules/label-has-for.md +130 -0
  106. package/docs/rules/lang.md +31 -0
  107. package/docs/rules/media-has-caption.md +48 -0
  108. package/docs/rules/mouse-events-have-key-events.md +58 -0
  109. package/docs/rules/no-access-key.md +30 -0
  110. package/docs/rules/no-aria-hidden-on-focusable.md +37 -0
  111. package/docs/rules/no-autofocus.md +43 -0
  112. package/docs/rules/no-distracting-elements.md +41 -0
  113. package/docs/rules/no-interactive-element-to-noninteractive-role.md +73 -0
  114. package/docs/rules/no-noninteractive-element-interactions.md +145 -0
  115. package/docs/rules/no-noninteractive-element-to-interactive-role.md +76 -0
  116. package/docs/rules/no-noninteractive-tabindex.md +115 -0
  117. package/docs/rules/no-onchange.md +36 -0
  118. package/docs/rules/no-redundant-roles.md +46 -0
  119. package/docs/rules/no-static-element-interactions.md +114 -0
  120. package/docs/rules/prefer-tag-over-role.md +32 -0
  121. package/docs/rules/role-has-required-aria-props.md +31 -0
  122. package/docs/rules/role-supports-aria-props.md +39 -0
  123. package/docs/rules/scope.md +30 -0
  124. package/docs/rules/tabindex-no-positive.md +32 -0
  125. package/lib/configs/flat-config-base.js +11 -0
  126. package/lib/configs/legacy-config-base.js +9 -0
  127. package/lib/index.js +209 -0
  128. package/lib/rules/accessible-emoji.js +63 -0
  129. package/lib/rules/alt-text.js +218 -0
  130. package/lib/rules/anchor-ambiguous-text.js +64 -0
  131. package/lib/rules/anchor-has-content.js +60 -0
  132. package/lib/rules/anchor-is-valid.js +122 -0
  133. package/lib/rules/aria-activedescendant-has-tabindex.js +66 -0
  134. package/lib/rules/aria-props.js +59 -0
  135. package/lib/rules/aria-proptypes.js +114 -0
  136. package/lib/rules/aria-role.js +89 -0
  137. package/lib/rules/aria-unsupported-elements.js +64 -0
  138. package/lib/rules/autocomplete-valid.js +67 -0
  139. package/lib/rules/click-events-have-key-events.js +68 -0
  140. package/lib/rules/control-has-associated-label.js +103 -0
  141. package/lib/rules/heading-has-content.js +61 -0
  142. package/lib/rules/html-has-lang.js +50 -0
  143. package/lib/rules/iframe-has-title.js +50 -0
  144. package/lib/rules/img-redundant-alt.js +88 -0
  145. package/lib/rules/interactive-supports-focus.js +87 -0
  146. package/lib/rules/label-has-associated-control.js +127 -0
  147. package/lib/rules/label-has-for.js +150 -0
  148. package/lib/rules/lang.js +68 -0
  149. package/lib/rules/media-has-caption.js +96 -0
  150. package/lib/rules/mouse-events-have-key-events.js +94 -0
  151. package/lib/rules/no-access-key.js +43 -0
  152. package/lib/rules/no-aria-hidden-on-focusable.js +47 -0
  153. package/lib/rules/no-autofocus.js +62 -0
  154. package/lib/rules/no-distracting-elements.js +54 -0
  155. package/lib/rules/no-interactive-element-to-noninteractive-role.js +81 -0
  156. package/lib/rules/no-noninteractive-element-interactions.js +95 -0
  157. package/lib/rules/no-noninteractive-element-to-interactive-role.js +80 -0
  158. package/lib/rules/no-noninteractive-tabindex.js +109 -0
  159. package/lib/rules/no-onchange.js +52 -0
  160. package/lib/rules/no-redundant-roles.js +86 -0
  161. package/lib/rules/no-static-element-interactions.js +102 -0
  162. package/lib/rules/prefer-tag-over-role.js +75 -0
  163. package/lib/rules/role-has-required-aria-props.js +88 -0
  164. package/lib/rules/role-supports-aria-props.js +78 -0
  165. package/lib/rules/scope.js +58 -0
  166. package/lib/rules/tabindex-no-positive.js +53 -0
  167. package/lib/util/attributesComparator.js +34 -0
  168. package/lib/util/getAccessibleChildText.js +55 -0
  169. package/lib/util/getComputedRole.js +19 -0
  170. package/lib/util/getElementType.js +30 -0
  171. package/lib/util/getExplicitRole.js +27 -0
  172. package/lib/util/getImplicitRole.js +24 -0
  173. package/lib/util/getSuggestion.js +32 -0
  174. package/lib/util/getTabIndex.js +34 -0
  175. package/lib/util/hasAccessibleChild.js +30 -0
  176. package/lib/util/implicitRoles/a.js +17 -0
  177. package/lib/util/implicitRoles/area.js +17 -0
  178. package/lib/util/implicitRoles/article.js +13 -0
  179. package/lib/util/implicitRoles/aside.js +13 -0
  180. package/lib/util/implicitRoles/body.js +13 -0
  181. package/lib/util/implicitRoles/button.js +13 -0
  182. package/lib/util/implicitRoles/datalist.js +13 -0
  183. package/lib/util/implicitRoles/details.js +13 -0
  184. package/lib/util/implicitRoles/dialog.js +13 -0
  185. package/lib/util/implicitRoles/form.js +13 -0
  186. package/lib/util/implicitRoles/h1.js +13 -0
  187. package/lib/util/implicitRoles/h2.js +13 -0
  188. package/lib/util/implicitRoles/h3.js +13 -0
  189. package/lib/util/implicitRoles/h4.js +13 -0
  190. package/lib/util/implicitRoles/h5.js +13 -0
  191. package/lib/util/implicitRoles/h6.js +13 -0
  192. package/lib/util/implicitRoles/hr.js +13 -0
  193. package/lib/util/implicitRoles/img.js +31 -0
  194. package/lib/util/implicitRoles/index.js +82 -0
  195. package/lib/util/implicitRoles/input.js +38 -0
  196. package/lib/util/implicitRoles/li.js +13 -0
  197. package/lib/util/implicitRoles/link.js +17 -0
  198. package/lib/util/implicitRoles/menu.js +19 -0
  199. package/lib/util/implicitRoles/menuitem.js +28 -0
  200. package/lib/util/implicitRoles/meter.js +13 -0
  201. package/lib/util/implicitRoles/nav.js +13 -0
  202. package/lib/util/implicitRoles/ol.js +13 -0
  203. package/lib/util/implicitRoles/option.js +13 -0
  204. package/lib/util/implicitRoles/output.js +13 -0
  205. package/lib/util/implicitRoles/progress.js +13 -0
  206. package/lib/util/implicitRoles/section.js +13 -0
  207. package/lib/util/implicitRoles/select.js +13 -0
  208. package/lib/util/implicitRoles/tbody.js +13 -0
  209. package/lib/util/implicitRoles/textarea.js +13 -0
  210. package/lib/util/implicitRoles/tfoot.js +13 -0
  211. package/lib/util/implicitRoles/thead.js +13 -0
  212. package/lib/util/implicitRoles/ul.js +13 -0
  213. package/lib/util/isAbstractRole.js +23 -0
  214. package/lib/util/isContentEditable.js +13 -0
  215. package/lib/util/isDOMElement.js +15 -0
  216. package/lib/util/isDisabledElement.js +23 -0
  217. package/lib/util/isFocusable.js +23 -0
  218. package/lib/util/isHiddenFromScreenReader.js +26 -0
  219. package/lib/util/isInteractiveElement.js +116 -0
  220. package/lib/util/isInteractiveRole.js +54 -0
  221. package/lib/util/isNonInteractiveElement.js +131 -0
  222. package/lib/util/isNonInteractiveRole.js +55 -0
  223. package/lib/util/isNonLiteralProperty.js +29 -0
  224. package/lib/util/isPresentationRole.js +13 -0
  225. package/lib/util/isSemanticRoleElement.js +54 -0
  226. package/lib/util/mayContainChildComponent.js +50 -0
  227. package/lib/util/mayHaveAccessibleLabel.js +95 -0
  228. package/lib/util/schemas.js +52 -0
  229. package/package.json +120 -0
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = void 0;
7
+ var _jsxAstUtils = require("jsx-ast-utils");
8
+ var _arrayIncludes = _interopRequireDefault(require("array-includes"));
9
+ var _schemas = require("../util/schemas");
10
+ var _getElementType = _interopRequireDefault(require("../util/getElementType"));
11
+ var _isDOMElement = _interopRequireDefault(require("../util/isDOMElement"));
12
+ var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
13
+ var _isInteractiveElement = _interopRequireDefault(require("../util/isInteractiveElement"));
14
+ var _isInteractiveRole = _interopRequireDefault(require("../util/isInteractiveRole"));
15
+ var _mayHaveAccessibleLabel = _interopRequireDefault(require("../util/mayHaveAccessibleLabel"));
16
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
17
+ /**
18
+ * @fileoverview Enforce controls are associated with a text label.
19
+ * @author Jesse Beach
20
+ *
21
+ *
22
+ */
23
+
24
+ // ----------------------------------------------------------------------------
25
+ // Rule Definition
26
+ // ----------------------------------------------------------------------------
27
+
28
+ var errorMessage = 'A control must be associated with a text label.';
29
+ var ignoreList = ['link'];
30
+ var schema = (0, _schemas.generateObjSchema)({
31
+ labelAttributes: _schemas.arraySchema,
32
+ controlComponents: _schemas.arraySchema,
33
+ ignoreElements: _schemas.arraySchema,
34
+ ignoreRoles: _schemas.arraySchema,
35
+ depth: {
36
+ description: 'JSX tree depth limit to check for accessible label',
37
+ type: 'integer',
38
+ minimum: 0
39
+ }
40
+ });
41
+ var _default = exports["default"] = {
42
+ meta: {
43
+ docs: {
44
+ description: 'Enforce that a control (an interactive element) has a text label.',
45
+ url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/control-has-associated-label.md'
46
+ },
47
+ schema: [schema]
48
+ },
49
+ create: function create(context) {
50
+ var elementType = (0, _getElementType["default"])(context);
51
+ var options = context.options[0] || {};
52
+ var _options$labelAttribu = options.labelAttributes,
53
+ labelAttributes = _options$labelAttribu === void 0 ? [] : _options$labelAttribu,
54
+ _options$controlCompo = options.controlComponents,
55
+ controlComponents = _options$controlCompo === void 0 ? [] : _options$controlCompo,
56
+ _options$ignoreElemen = options.ignoreElements,
57
+ ignoreElements = _options$ignoreElemen === void 0 ? [] : _options$ignoreElemen,
58
+ _options$ignoreRoles = options.ignoreRoles,
59
+ ignoreRoles = _options$ignoreRoles === void 0 ? [] : _options$ignoreRoles;
60
+ var newIgnoreElements = new Set([].concat(ignoreElements, ignoreList));
61
+ var rule = function rule(node) {
62
+ var tag = elementType(node.openingElement);
63
+ var role = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.openingElement.attributes, 'role'));
64
+ // Ignore interactive elements that might get their label from a source
65
+ // that cannot be discerned from static analysis, like
66
+ // <label><input />Save</label>
67
+ if (newIgnoreElements.has(tag)) {
68
+ return;
69
+ }
70
+ // Ignore roles that are "interactive" but should not require a label.
71
+ if ((0, _arrayIncludes["default"])(ignoreRoles, role)) {
72
+ return;
73
+ }
74
+ var props = node.openingElement.attributes;
75
+ var nodeIsDOMElement = (0, _isDOMElement["default"])(tag);
76
+ var nodeIsHiddenFromScreenReader = (0, _isHiddenFromScreenReader["default"])(tag, props);
77
+ var nodeIsInteractiveElement = (0, _isInteractiveElement["default"])(tag, props);
78
+ var nodeIsInteractiveRole = (0, _isInteractiveRole["default"])(tag, props);
79
+ var nodeIsControlComponent = controlComponents.indexOf(tag) > -1;
80
+ if (nodeIsHiddenFromScreenReader) {
81
+ return;
82
+ }
83
+ var hasAccessibleLabel = true;
84
+ if (nodeIsInteractiveElement || nodeIsDOMElement && nodeIsInteractiveRole || nodeIsControlComponent) {
85
+ // Prevent crazy recursion.
86
+ var recursionDepth = Math.min(options.depth === undefined ? 2 : options.depth, 25);
87
+ hasAccessibleLabel = (0, _mayHaveAccessibleLabel["default"])(node, recursionDepth, labelAttributes, elementType, controlComponents);
88
+ }
89
+ if (!hasAccessibleLabel) {
90
+ context.report({
91
+ node: node.openingElement,
92
+ message: errorMessage
93
+ });
94
+ }
95
+ };
96
+
97
+ // Create visitor selectors.
98
+ return {
99
+ JSXElement: rule
100
+ };
101
+ }
102
+ };
103
+ module.exports = exports.default;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = void 0;
7
+ var _schemas = require("../util/schemas");
8
+ var _getElementType = _interopRequireDefault(require("../util/getElementType"));
9
+ var _hasAccessibleChild = _interopRequireDefault(require("../util/hasAccessibleChild"));
10
+ var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
11
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
12
+ /**
13
+ * @fileoverview Enforce heading (h1, h2, etc) elements contain accessible content.
14
+ * @author Ethan Cohen
15
+ */
16
+
17
+ // ----------------------------------------------------------------------------
18
+ // Rule Definition
19
+ // ----------------------------------------------------------------------------
20
+
21
+ var errorMessage = 'Headings must have content and the content must be accessible by a screen reader.';
22
+ var headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
23
+ var schema = (0, _schemas.generateObjSchema)({
24
+ components: _schemas.arraySchema
25
+ });
26
+ var _default = exports["default"] = {
27
+ meta: {
28
+ docs: {
29
+ url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/heading-has-content.md',
30
+ description: 'Enforce heading (`h1`, `h2`, etc) elements contain accessible content.'
31
+ },
32
+ schema: [schema]
33
+ },
34
+ create: function create(context) {
35
+ var elementType = (0, _getElementType["default"])(context);
36
+ return {
37
+ JSXOpeningElement: function JSXOpeningElement(node) {
38
+ var options = context.options[0] || {};
39
+ var componentOptions = options.components || [];
40
+ var typeCheck = headings.concat(componentOptions);
41
+ var nodeType = elementType(node);
42
+
43
+ // Only check 'h*' elements and custom types.
44
+ if (typeCheck.indexOf(nodeType) === -1) {
45
+ return;
46
+ }
47
+ if ((0, _hasAccessibleChild["default"])(node.parent, elementType)) {
48
+ return;
49
+ }
50
+ if ((0, _isHiddenFromScreenReader["default"])(nodeType, node.attributes)) {
51
+ return;
52
+ }
53
+ context.report({
54
+ node,
55
+ message: errorMessage
56
+ });
57
+ }
58
+ };
59
+ }
60
+ };
61
+ module.exports = exports.default;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
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
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
11
+ /**
12
+ * @fileoverview Enforce html element has lang prop.
13
+ * @author Ethan Cohen
14
+ */
15
+
16
+ // ----------------------------------------------------------------------------
17
+ // Rule Definition
18
+ // ----------------------------------------------------------------------------
19
+
20
+ var errorMessage = '<html> elements must have the lang prop.';
21
+ var schema = (0, _schemas.generateObjSchema)();
22
+ var _default = exports["default"] = {
23
+ meta: {
24
+ docs: {
25
+ url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/html-has-lang.md',
26
+ description: 'Enforce `<html>` element has `lang` prop.'
27
+ },
28
+ schema: [schema]
29
+ },
30
+ create: function create(context) {
31
+ var elementType = (0, _getElementType["default"])(context);
32
+ return {
33
+ JSXOpeningElement: function JSXOpeningElement(node) {
34
+ var type = elementType(node);
35
+ if (type && type !== 'html') {
36
+ return;
37
+ }
38
+ var lang = (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'lang'));
39
+ if (lang) {
40
+ return;
41
+ }
42
+ context.report({
43
+ node,
44
+ message: errorMessage
45
+ });
46
+ }
47
+ };
48
+ }
49
+ };
50
+ module.exports = exports.default;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = void 0;
7
+ var _jsxAstUtils = require("jsx-ast-utils");
8
+ var _getElementType = _interopRequireDefault(require("../util/getElementType"));
9
+ var _schemas = require("../util/schemas");
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
11
+ /**
12
+ * @fileoverview Enforce iframe elements have a title attribute.
13
+ * @author Ethan Cohen
14
+ */
15
+
16
+ // ----------------------------------------------------------------------------
17
+ // Rule Definition
18
+ // ----------------------------------------------------------------------------
19
+
20
+ var errorMessage = '<iframe> elements must have a unique title property.';
21
+ var schema = (0, _schemas.generateObjSchema)();
22
+ var _default = exports["default"] = {
23
+ meta: {
24
+ docs: {
25
+ url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/iframe-has-title.md',
26
+ description: 'Enforce iframe elements have a title attribute.'
27
+ },
28
+ schema: [schema]
29
+ },
30
+ create: function create(context) {
31
+ var elementType = (0, _getElementType["default"])(context);
32
+ return {
33
+ JSXOpeningElement: function JSXOpeningElement(node) {
34
+ var type = elementType(node);
35
+ if (type && type !== 'iframe') {
36
+ return;
37
+ }
38
+ var title = (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'title'));
39
+ if (title && typeof title === 'string') {
40
+ return;
41
+ }
42
+ context.report({
43
+ node,
44
+ message: errorMessage
45
+ });
46
+ }
47
+ };
48
+ }
49
+ };
50
+ module.exports = exports.default;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = void 0;
7
+ var _jsxAstUtils = require("jsx-ast-utils");
8
+ var _arrayIncludes = _interopRequireDefault(require("array-includes"));
9
+ var _stringPrototype = _interopRequireDefault(require("string.prototype.includes"));
10
+ var _safeRegexTest = _interopRequireDefault(require("safe-regex-test"));
11
+ var _schemas = require("../util/schemas");
12
+ var _getElementType = _interopRequireDefault(require("../util/getElementType"));
13
+ var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
14
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
15
+ /**
16
+ * @fileoverview Enforce img alt attribute does not have the word image, picture, or photo.
17
+ * @author Ethan Cohen
18
+ */
19
+
20
+ // ----------------------------------------------------------------------------
21
+ // Rule Definition
22
+ // ----------------------------------------------------------------------------
23
+
24
+ var REDUNDANT_WORDS = ['image', 'photo', 'picture'];
25
+ var errorMessage = 'Redundant alt attribute. Screen-readers already announce `img` tags as an image. You don’t need to use the words `image`, `photo,` or `picture` (or any specified custom words) in the alt prop.';
26
+ var schema = (0, _schemas.generateObjSchema)({
27
+ components: _schemas.arraySchema,
28
+ words: _schemas.arraySchema
29
+ });
30
+ var isASCII = (0, _safeRegexTest["default"])(/[\x20-\x7F]+/);
31
+ function containsRedundantWord(value, redundantWords) {
32
+ var lowercaseRedundantWords = redundantWords.map(function (redundantWord) {
33
+ return redundantWord.toLowerCase();
34
+ });
35
+ if (isASCII(value)) {
36
+ return value.split(/\s+/).some(function (valueWord) {
37
+ return (0, _arrayIncludes["default"])(lowercaseRedundantWords, valueWord.toLowerCase());
38
+ });
39
+ }
40
+ return lowercaseRedundantWords.some(function (redundantWord) {
41
+ return (0, _stringPrototype["default"])(value.toLowerCase(), redundantWord);
42
+ });
43
+ }
44
+ var _default = exports["default"] = {
45
+ meta: {
46
+ docs: {
47
+ url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/img-redundant-alt.md',
48
+ description: 'Enforce `<img>` alt prop does not contain the word "image", "picture", or "photo".'
49
+ },
50
+ schema: [schema]
51
+ },
52
+ create: function create(context) {
53
+ var elementType = (0, _getElementType["default"])(context);
54
+ return {
55
+ JSXOpeningElement: function JSXOpeningElement(node) {
56
+ var options = context.options[0] || {};
57
+ var componentOptions = options.components || [];
58
+ var typesToValidate = ['img'].concat(componentOptions);
59
+ var nodeType = elementType(node);
60
+
61
+ // Only check 'label' elements and custom types.
62
+ if (typesToValidate.indexOf(nodeType) === -1) {
63
+ return;
64
+ }
65
+ var altProp = (0, _jsxAstUtils.getProp)(node.attributes, 'alt');
66
+ // Return if alt prop is not present.
67
+ if (altProp === undefined) {
68
+ return;
69
+ }
70
+ var value = (0, _jsxAstUtils.getLiteralPropValue)(altProp);
71
+ var isVisible = (0, _isHiddenFromScreenReader["default"])(nodeType, node.attributes) === false;
72
+ var _options$words = options.words,
73
+ words = _options$words === void 0 ? [] : _options$words;
74
+ var redundantWords = REDUNDANT_WORDS.concat(words);
75
+ if (typeof value === 'string' && isVisible) {
76
+ var hasRedundancy = containsRedundantWord(value, redundantWords);
77
+ if (hasRedundancy === true) {
78
+ context.report({
79
+ node,
80
+ message: errorMessage
81
+ });
82
+ }
83
+ }
84
+ }
85
+ };
86
+ }
87
+ };
88
+ module.exports = exports.default;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = void 0;
7
+ var _ariaQuery = require("aria-query");
8
+ var _jsxAstUtils = require("jsx-ast-utils");
9
+ var _arrayIncludes = _interopRequireDefault(require("array-includes"));
10
+ var _schemas = require("../util/schemas");
11
+ var _getElementType = _interopRequireDefault(require("../util/getElementType"));
12
+ var _isDisabledElement = _interopRequireDefault(require("../util/isDisabledElement"));
13
+ var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
14
+ var _isInteractiveElement = _interopRequireDefault(require("../util/isInteractiveElement"));
15
+ var _isInteractiveRole = _interopRequireDefault(require("../util/isInteractiveRole"));
16
+ var _isNonInteractiveElement = _interopRequireDefault(require("../util/isNonInteractiveElement"));
17
+ var _isNonInteractiveRole = _interopRequireDefault(require("../util/isNonInteractiveRole"));
18
+ var _isPresentationRole = _interopRequireDefault(require("../util/isPresentationRole"));
19
+ var _getTabIndex = _interopRequireDefault(require("../util/getTabIndex"));
20
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
21
+ /**
22
+ * @fileoverview Enforce that elements with onClick handlers must be tabbable.
23
+ * @author Ethan Cohen
24
+ *
25
+ */
26
+
27
+ // ----------------------------------------------------------------------------
28
+ // Rule Definition
29
+ // ----------------------------------------------------------------------------
30
+
31
+ var schema = (0, _schemas.generateObjSchema)({
32
+ tabbable: (0, _schemas.enumArraySchema)(_ariaQuery.roles.keys().filter(function (name) {
33
+ return !_ariaQuery.roles.get(name)["abstract"] && _ariaQuery.roles.get(name).superClass.some(function (klasses) {
34
+ return (0, _arrayIncludes["default"])(klasses, 'widget');
35
+ });
36
+ }))
37
+ });
38
+ var interactiveProps = [].concat(_jsxAstUtils.eventHandlersByType.mouse, _jsxAstUtils.eventHandlersByType.keyboard);
39
+ var _default = exports["default"] = {
40
+ meta: {
41
+ docs: {
42
+ url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/interactive-supports-focus.md',
43
+ description: 'Enforce that elements with interactive handlers like `onClick` must be focusable.'
44
+ },
45
+ schema: [schema]
46
+ },
47
+ create: function create(context) {
48
+ var elementType = (0, _getElementType["default"])(context);
49
+ return {
50
+ JSXOpeningElement: function JSXOpeningElement(node) {
51
+ var tabbable = context.options && context.options[0] && context.options[0].tabbable || [];
52
+ var attributes = node.attributes;
53
+ var type = elementType(node);
54
+ var hasInteractiveProps = (0, _jsxAstUtils.hasAnyProp)(attributes, interactiveProps);
55
+ var hasTabindex = (0, _getTabIndex["default"])((0, _jsxAstUtils.getProp)(attributes, 'tabIndex')) !== undefined;
56
+ if (!_ariaQuery.dom.has(type)) {
57
+ // Do not test higher level JSX components, as we do not know what
58
+ // low-level DOM element this maps to.
59
+ return;
60
+ }
61
+ if (!hasInteractiveProps || (0, _isDisabledElement["default"])(attributes) || (0, _isHiddenFromScreenReader["default"])(type, attributes) || (0, _isPresentationRole["default"])(type, attributes)) {
62
+ // Presentation is an intentional signal from the author that this
63
+ // element is not meant to be perceivable. For example, a click screen
64
+ // to close a dialog .
65
+ return;
66
+ }
67
+ if (hasInteractiveProps && (0, _isInteractiveRole["default"])(type, attributes) && !(0, _isInteractiveElement["default"])(type, attributes) && !(0, _isNonInteractiveElement["default"])(type, attributes) && !(0, _isNonInteractiveRole["default"])(type, attributes) && !hasTabindex) {
68
+ var role = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(attributes, 'role'));
69
+ if ((0, _arrayIncludes["default"])(tabbable, role)) {
70
+ // Always tabbable, tabIndex = 0
71
+ context.report({
72
+ node,
73
+ message: "Elements with the '".concat(role, "' interactive role must be tabbable.")
74
+ });
75
+ } else {
76
+ // Focusable, tabIndex = -1 or 0
77
+ context.report({
78
+ node,
79
+ message: "Elements with the '".concat(role, "' interactive role must be focusable.")
80
+ });
81
+ }
82
+ }
83
+ }
84
+ };
85
+ }
86
+ };
87
+ module.exports = exports.default;
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+
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
+ var _mayContainChildComponent = _interopRequireDefault(require("../util/mayContainChildComponent"));
11
+ var _mayHaveAccessibleLabel = _interopRequireDefault(require("../util/mayHaveAccessibleLabel"));
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
13
+ /**
14
+ * @fileoverview Enforce label tags have an associated control.
15
+ * @author Jesse Beach
16
+ *
17
+ *
18
+ */
19
+
20
+ // ----------------------------------------------------------------------------
21
+ // Rule Definition
22
+ // ----------------------------------------------------------------------------
23
+
24
+ var errorMessage = 'A form label must be associated with a control.';
25
+ var errorMessageNoLabel = 'A form label must have accessible text.';
26
+ var schema = (0, _schemas.generateObjSchema)({
27
+ labelComponents: _schemas.arraySchema,
28
+ labelAttributes: _schemas.arraySchema,
29
+ controlComponents: _schemas.arraySchema,
30
+ assert: {
31
+ description: 'Assert that the label has htmlFor, a nested label, both or either',
32
+ type: 'string',
33
+ "enum": ['htmlFor', 'nesting', 'both', 'either']
34
+ },
35
+ depth: {
36
+ description: 'JSX tree depth limit to check for accessible label',
37
+ type: 'integer',
38
+ minimum: 0
39
+ }
40
+ });
41
+ function validateID(node, context) {
42
+ var _settings$jsxA11y$at, _settings$jsxA11y, _settings$jsxA11y$att;
43
+ var settings = context.settings;
44
+ var htmlForAttributes = (_settings$jsxA11y$at = (_settings$jsxA11y = settings['jsx-a11y']) === null || _settings$jsxA11y === void 0 ? void 0 : (_settings$jsxA11y$att = _settings$jsxA11y.attributes) === null || _settings$jsxA11y$att === void 0 ? void 0 : _settings$jsxA11y$att["for"]) !== null && _settings$jsxA11y$at !== void 0 ? _settings$jsxA11y$at : ['htmlFor'];
45
+ for (var i = 0; i < htmlForAttributes.length; i += 1) {
46
+ var attribute = htmlForAttributes[i];
47
+ if ((0, _jsxAstUtils.hasProp)(node.attributes, attribute)) {
48
+ var htmlForAttr = (0, _jsxAstUtils.getProp)(node.attributes, attribute);
49
+ var htmlForValue = (0, _jsxAstUtils.getPropValue)(htmlForAttr);
50
+ return htmlForAttr !== false && !!htmlForValue;
51
+ }
52
+ }
53
+ return false;
54
+ }
55
+ var _default = exports["default"] = {
56
+ meta: {
57
+ docs: {
58
+ description: 'Enforce that a `label` tag has a text label and an associated control.',
59
+ url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/label-has-associated-control.md'
60
+ },
61
+ schema: [schema]
62
+ },
63
+ create: function create(context) {
64
+ var options = context.options[0] || {};
65
+ var labelComponents = options.labelComponents || [];
66
+ var assertType = options.assert || 'either';
67
+ var componentNames = ['label'].concat(labelComponents);
68
+ var elementType = (0, _getElementType["default"])(context);
69
+ var rule = function rule(node) {
70
+ if (componentNames.indexOf(elementType(node.openingElement)) === -1) {
71
+ return;
72
+ }
73
+ var controlComponents = ['input', 'meter', 'output', 'progress', 'select', 'textarea'].concat(options.controlComponents || []);
74
+ // Prevent crazy recursion.
75
+ var recursionDepth = Math.min(options.depth === undefined ? 2 : options.depth, 25);
76
+ var hasLabelId = validateID(node.openingElement, context);
77
+ // Check for multiple control components.
78
+ var hasNestedControl = controlComponents.some(function (name) {
79
+ return (0, _mayContainChildComponent["default"])(node, name, recursionDepth, elementType);
80
+ });
81
+ var hasAccessibleLabel = (0, _mayHaveAccessibleLabel["default"])(node, recursionDepth, options.labelAttributes, elementType, controlComponents);
82
+ if (!hasAccessibleLabel) {
83
+ context.report({
84
+ node: node.openingElement,
85
+ message: errorMessageNoLabel
86
+ });
87
+ return;
88
+ }
89
+ switch (assertType) {
90
+ case 'htmlFor':
91
+ if (hasLabelId) {
92
+ return;
93
+ }
94
+ break;
95
+ case 'nesting':
96
+ if (hasNestedControl) {
97
+ return;
98
+ }
99
+ break;
100
+ case 'both':
101
+ if (hasLabelId && hasNestedControl) {
102
+ return;
103
+ }
104
+ break;
105
+ case 'either':
106
+ if (hasLabelId || hasNestedControl) {
107
+ return;
108
+ }
109
+ break;
110
+ default:
111
+ break;
112
+ }
113
+
114
+ // htmlFor case
115
+ context.report({
116
+ node: node.openingElement,
117
+ message: errorMessage
118
+ });
119
+ };
120
+
121
+ // Create visitor selectors.
122
+ return {
123
+ JSXElement: rule
124
+ };
125
+ }
126
+ };
127
+ module.exports = exports.default;