@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.
- package/.babelrc +17 -0
- package/.eslintrc +44 -0
- package/CHANGELOG.md +774 -0
- package/LICENSE.md +8 -0
- package/README.md +423 -0
- package/__mocks__/IdentifierMock.js +15 -0
- package/__mocks__/JSXAttributeMock.js +39 -0
- package/__mocks__/JSXElementMock.js +37 -0
- package/__mocks__/JSXExpressionContainerMock.js +15 -0
- package/__mocks__/JSXSpreadAttributeMock.js +18 -0
- package/__mocks__/JSXTextMock.js +17 -0
- package/__mocks__/LiteralMock.js +17 -0
- package/__mocks__/genInteractives.js +218 -0
- package/__tests__/__util__/axeMapping.js +6 -0
- package/__tests__/__util__/helpers/getESLintCoreRule.js +9 -0
- package/__tests__/__util__/helpers/parsers.js +186 -0
- package/__tests__/__util__/parserOptionsMapper.js +53 -0
- package/__tests__/__util__/ruleOptionsMapperFactory.js +33 -0
- package/__tests__/index-test.js +40 -0
- package/__tests__/src/rules/accessible-emoji-test.js +66 -0
- package/__tests__/src/rules/alt-text-test.js +291 -0
- package/__tests__/src/rules/anchor-ambiguous-text-test.js +117 -0
- package/__tests__/src/rules/anchor-has-content-test.js +54 -0
- package/__tests__/src/rules/anchor-is-valid-test.js +532 -0
- package/__tests__/src/rules/aria-activedescendant-has-tabindex-test.js +95 -0
- package/__tests__/src/rules/aria-props-test.js +69 -0
- package/__tests__/src/rules/aria-proptypes-test.js +311 -0
- package/__tests__/src/rules/aria-role-test.js +118 -0
- package/__tests__/src/rules/aria-unsupported-elements-test.js +75 -0
- package/__tests__/src/rules/autocomplete-valid-test.js +77 -0
- package/__tests__/src/rules/click-events-have-key-events-test.js +77 -0
- package/__tests__/src/rules/control-has-associated-label-test.js +327 -0
- package/__tests__/src/rules/heading-has-content-test.js +85 -0
- package/__tests__/src/rules/html-has-lang-test.js +42 -0
- package/__tests__/src/rules/iframe-has-title-test.js +55 -0
- package/__tests__/src/rules/img-redundant-alt-test.js +137 -0
- package/__tests__/src/rules/interactive-supports-focus-test.js +267 -0
- package/__tests__/src/rules/label-has-associated-control-test.js +243 -0
- package/__tests__/src/rules/label-has-for-test.js +235 -0
- package/__tests__/src/rules/lang-test.js +59 -0
- package/__tests__/src/rules/media-has-caption-test.js +220 -0
- package/__tests__/src/rules/mouse-events-have-key-events-test.js +154 -0
- package/__tests__/src/rules/no-access-key-test.js +48 -0
- package/__tests__/src/rules/no-aria-hidden-on-focusable-test.js +44 -0
- package/__tests__/src/rules/no-autofocus-test.js +68 -0
- package/__tests__/src/rules/no-distracting-elements-test.js +51 -0
- package/__tests__/src/rules/no-interactive-element-to-noninteractive-role-test.js +405 -0
- package/__tests__/src/rules/no-noninteractive-element-interactions-test.js +502 -0
- package/__tests__/src/rules/no-noninteractive-element-to-interactive-role-test.js +500 -0
- package/__tests__/src/rules/no-noninteractive-tabindex-test.js +123 -0
- package/__tests__/src/rules/no-onchange-test.js +57 -0
- package/__tests__/src/rules/no-redundant-roles-test.js +98 -0
- package/__tests__/src/rules/no-static-element-interactions-test.js +501 -0
- package/__tests__/src/rules/prefer-tag-over-role-test.js +63 -0
- package/__tests__/src/rules/role-has-required-aria-props-test.js +134 -0
- package/__tests__/src/rules/role-supports-aria-props-test.js +570 -0
- package/__tests__/src/rules/scope-test.js +50 -0
- package/__tests__/src/rules/tabindex-no-positive-test.js +55 -0
- package/__tests__/src/util/attributesComparator-test.js +91 -0
- package/__tests__/src/util/getAccessibleChildText-test.js +174 -0
- package/__tests__/src/util/getComputedRole-test.js +71 -0
- package/__tests__/src/util/getElementType-test.js +154 -0
- package/__tests__/src/util/getExplicitRole-test.js +35 -0
- package/__tests__/src/util/getImplicitRole-test.js +25 -0
- package/__tests__/src/util/getSuggestion-test.js +33 -0
- package/__tests__/src/util/getTabIndex-test.js +85 -0
- package/__tests__/src/util/hasAccessibleChild-test.js +157 -0
- package/__tests__/src/util/implicitRoles/input-test.js +87 -0
- package/__tests__/src/util/implicitRoles/menu-test.js +20 -0
- package/__tests__/src/util/implicitRoles/menuitem-test.js +38 -0
- package/__tests__/src/util/isAbstractRole-test.js +51 -0
- package/__tests__/src/util/isContentEditable-test.js +52 -0
- package/__tests__/src/util/isDOMElement-test.js +30 -0
- package/__tests__/src/util/isDisabledElement-test.js +88 -0
- package/__tests__/src/util/isFocusable-test.js +111 -0
- package/__tests__/src/util/isInteractiveElement-test.js +104 -0
- package/__tests__/src/util/isInteractiveRole-test.js +59 -0
- package/__tests__/src/util/isNonInteractiveElement-test.js +97 -0
- package/__tests__/src/util/isNonInteractiveRole-test.js +59 -0
- package/__tests__/src/util/isNonLiteralProperty-test.js +52 -0
- package/__tests__/src/util/isSemanticRoleElement-test.js +72 -0
- package/__tests__/src/util/mayContainChildComponent-test.js +219 -0
- package/__tests__/src/util/mayHaveAccessibleLabel-test.js +256 -0
- package/__tests__/src/util/parserOptionsMapper-test.js +93 -0
- package/__tests__/src/util/schemas-test.js +35 -0
- package/docs/rules/accessible-emoji.md +30 -0
- package/docs/rules/alt-text.md +168 -0
- package/docs/rules/anchor-ambiguous-text.md +91 -0
- package/docs/rules/anchor-has-content.md +64 -0
- package/docs/rules/anchor-is-valid.md +270 -0
- package/docs/rules/aria-activedescendant-has-tabindex.md +52 -0
- package/docs/rules/aria-props.md +29 -0
- package/docs/rules/aria-proptypes.md +30 -0
- package/docs/rules/aria-role.md +51 -0
- package/docs/rules/aria-unsupported-elements.md +30 -0
- package/docs/rules/autocomplete-valid.md +49 -0
- package/docs/rules/click-events-have-key-events.md +28 -0
- package/docs/rules/control-has-associated-label.md +113 -0
- package/docs/rules/heading-has-content.md +67 -0
- package/docs/rules/html-has-lang.md +31 -0
- package/docs/rules/iframe-has-title.md +37 -0
- package/docs/rules/img-redundant-alt.md +48 -0
- package/docs/rules/interactive-supports-focus.md +156 -0
- package/docs/rules/label-has-associated-control.md +152 -0
- package/docs/rules/label-has-for.md +130 -0
- package/docs/rules/lang.md +31 -0
- package/docs/rules/media-has-caption.md +48 -0
- package/docs/rules/mouse-events-have-key-events.md +58 -0
- package/docs/rules/no-access-key.md +30 -0
- package/docs/rules/no-aria-hidden-on-focusable.md +37 -0
- package/docs/rules/no-autofocus.md +43 -0
- package/docs/rules/no-distracting-elements.md +41 -0
- package/docs/rules/no-interactive-element-to-noninteractive-role.md +73 -0
- package/docs/rules/no-noninteractive-element-interactions.md +145 -0
- package/docs/rules/no-noninteractive-element-to-interactive-role.md +76 -0
- package/docs/rules/no-noninteractive-tabindex.md +115 -0
- package/docs/rules/no-onchange.md +36 -0
- package/docs/rules/no-redundant-roles.md +46 -0
- package/docs/rules/no-static-element-interactions.md +114 -0
- package/docs/rules/prefer-tag-over-role.md +32 -0
- package/docs/rules/role-has-required-aria-props.md +31 -0
- package/docs/rules/role-supports-aria-props.md +39 -0
- package/docs/rules/scope.md +30 -0
- package/docs/rules/tabindex-no-positive.md +32 -0
- package/lib/configs/flat-config-base.js +11 -0
- package/lib/configs/legacy-config-base.js +9 -0
- package/lib/index.js +209 -0
- package/lib/rules/accessible-emoji.js +63 -0
- package/lib/rules/alt-text.js +218 -0
- package/lib/rules/anchor-ambiguous-text.js +64 -0
- package/lib/rules/anchor-has-content.js +60 -0
- package/lib/rules/anchor-is-valid.js +122 -0
- package/lib/rules/aria-activedescendant-has-tabindex.js +66 -0
- package/lib/rules/aria-props.js +59 -0
- package/lib/rules/aria-proptypes.js +114 -0
- package/lib/rules/aria-role.js +89 -0
- package/lib/rules/aria-unsupported-elements.js +64 -0
- package/lib/rules/autocomplete-valid.js +67 -0
- package/lib/rules/click-events-have-key-events.js +68 -0
- package/lib/rules/control-has-associated-label.js +103 -0
- package/lib/rules/heading-has-content.js +61 -0
- package/lib/rules/html-has-lang.js +50 -0
- package/lib/rules/iframe-has-title.js +50 -0
- package/lib/rules/img-redundant-alt.js +88 -0
- package/lib/rules/interactive-supports-focus.js +87 -0
- package/lib/rules/label-has-associated-control.js +127 -0
- package/lib/rules/label-has-for.js +150 -0
- package/lib/rules/lang.js +68 -0
- package/lib/rules/media-has-caption.js +96 -0
- package/lib/rules/mouse-events-have-key-events.js +94 -0
- package/lib/rules/no-access-key.js +43 -0
- package/lib/rules/no-aria-hidden-on-focusable.js +47 -0
- package/lib/rules/no-autofocus.js +62 -0
- package/lib/rules/no-distracting-elements.js +54 -0
- package/lib/rules/no-interactive-element-to-noninteractive-role.js +81 -0
- package/lib/rules/no-noninteractive-element-interactions.js +95 -0
- package/lib/rules/no-noninteractive-element-to-interactive-role.js +80 -0
- package/lib/rules/no-noninteractive-tabindex.js +109 -0
- package/lib/rules/no-onchange.js +52 -0
- package/lib/rules/no-redundant-roles.js +86 -0
- package/lib/rules/no-static-element-interactions.js +102 -0
- package/lib/rules/prefer-tag-over-role.js +75 -0
- package/lib/rules/role-has-required-aria-props.js +88 -0
- package/lib/rules/role-supports-aria-props.js +78 -0
- package/lib/rules/scope.js +58 -0
- package/lib/rules/tabindex-no-positive.js +53 -0
- package/lib/util/attributesComparator.js +34 -0
- package/lib/util/getAccessibleChildText.js +55 -0
- package/lib/util/getComputedRole.js +19 -0
- package/lib/util/getElementType.js +30 -0
- package/lib/util/getExplicitRole.js +27 -0
- package/lib/util/getImplicitRole.js +24 -0
- package/lib/util/getSuggestion.js +32 -0
- package/lib/util/getTabIndex.js +34 -0
- package/lib/util/hasAccessibleChild.js +30 -0
- package/lib/util/implicitRoles/a.js +17 -0
- package/lib/util/implicitRoles/area.js +17 -0
- package/lib/util/implicitRoles/article.js +13 -0
- package/lib/util/implicitRoles/aside.js +13 -0
- package/lib/util/implicitRoles/body.js +13 -0
- package/lib/util/implicitRoles/button.js +13 -0
- package/lib/util/implicitRoles/datalist.js +13 -0
- package/lib/util/implicitRoles/details.js +13 -0
- package/lib/util/implicitRoles/dialog.js +13 -0
- package/lib/util/implicitRoles/form.js +13 -0
- package/lib/util/implicitRoles/h1.js +13 -0
- package/lib/util/implicitRoles/h2.js +13 -0
- package/lib/util/implicitRoles/h3.js +13 -0
- package/lib/util/implicitRoles/h4.js +13 -0
- package/lib/util/implicitRoles/h5.js +13 -0
- package/lib/util/implicitRoles/h6.js +13 -0
- package/lib/util/implicitRoles/hr.js +13 -0
- package/lib/util/implicitRoles/img.js +31 -0
- package/lib/util/implicitRoles/index.js +82 -0
- package/lib/util/implicitRoles/input.js +38 -0
- package/lib/util/implicitRoles/li.js +13 -0
- package/lib/util/implicitRoles/link.js +17 -0
- package/lib/util/implicitRoles/menu.js +19 -0
- package/lib/util/implicitRoles/menuitem.js +28 -0
- package/lib/util/implicitRoles/meter.js +13 -0
- package/lib/util/implicitRoles/nav.js +13 -0
- package/lib/util/implicitRoles/ol.js +13 -0
- package/lib/util/implicitRoles/option.js +13 -0
- package/lib/util/implicitRoles/output.js +13 -0
- package/lib/util/implicitRoles/progress.js +13 -0
- package/lib/util/implicitRoles/section.js +13 -0
- package/lib/util/implicitRoles/select.js +13 -0
- package/lib/util/implicitRoles/tbody.js +13 -0
- package/lib/util/implicitRoles/textarea.js +13 -0
- package/lib/util/implicitRoles/tfoot.js +13 -0
- package/lib/util/implicitRoles/thead.js +13 -0
- package/lib/util/implicitRoles/ul.js +13 -0
- package/lib/util/isAbstractRole.js +23 -0
- package/lib/util/isContentEditable.js +13 -0
- package/lib/util/isDOMElement.js +15 -0
- package/lib/util/isDisabledElement.js +23 -0
- package/lib/util/isFocusable.js +23 -0
- package/lib/util/isHiddenFromScreenReader.js +26 -0
- package/lib/util/isInteractiveElement.js +116 -0
- package/lib/util/isInteractiveRole.js +54 -0
- package/lib/util/isNonInteractiveElement.js +131 -0
- package/lib/util/isNonInteractiveRole.js +55 -0
- package/lib/util/isNonLiteralProperty.js +29 -0
- package/lib/util/isPresentationRole.js +13 -0
- package/lib/util/isSemanticRoleElement.js +54 -0
- package/lib/util/mayContainChildComponent.js +50 -0
- package/lib/util/mayHaveAccessibleLabel.js +95 -0
- package/lib/util/schemas.js +52 -0
- 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;
|