UNPKG

6.54 kBJavaScriptView Raw
1"use strict";
2var __extends = (this && this.__extends) || (function () {
3 var extendStatics = function (d, b) {
4 extendStatics = Object.setPrototypeOf ||
5 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
7 return extendStatics(d, b);
8 }
9 return function (d, b) {
10 extendStatics(d, b);
11 function __() { this.constructor = d; }
12 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13 };
14})();
15Object.defineProperty(exports, "__esModule", { value: true });
16var ts = require("typescript");
17var Lint = require("tslint");
18var tsutils = require("tsutils");
19var getImplicitRole_1 = require("./utils/getImplicitRole");
20var JsxAttribute_1 = require("./utils/JsxAttribute");
21var ROLE_SCHEMA = require('./utils/attributes/roleSchema.json');
22var ARIA_ATTRIBUTES = require('./utils/attributes/ariaSchema.json');
23var ROLES = ROLE_SCHEMA.roles;
24var ROLE_STRING = 'role';
25function getFailureStringForNotImplicitRole(roleNamesInElement, invalidPropNames) {
26 return "Attribute(s) " + invalidPropNames.join(', ') + " are not supported by role(s) " + roleNamesInElement.join(', ') + ". You are using incorrect role or incorrect aria-* attribute";
27}
28exports.getFailureStringForNotImplicitRole = getFailureStringForNotImplicitRole;
29function getFailureStringForImplicitRole(tagName, roleName, invalidPropNames) {
30 return "Attribute(s) " + invalidPropNames.join(', ') + " not supported by role " + roleName + " which is implicitly set by the HTML tag " + tagName + ".";
31}
32exports.getFailureStringForImplicitRole = getFailureStringForImplicitRole;
33function getFailureStringForNoRole(tagName, invalidPropNames) {
34 return "Attribute(s) " + invalidPropNames + " are not supported by no corresponding role. There is no corresponding role for the HTML tag " + tagName + ". A reference about no corresponding role: https://www.w3.org/TR/html-aria/#dfn-no-corresponding-role.";
35}
36exports.getFailureStringForNoRole = getFailureStringForNoRole;
37var Rule = (function (_super) {
38 __extends(Rule, _super);
39 function Rule() {
40 return _super !== null && _super.apply(this, arguments) || this;
41 }
42 Rule.prototype.apply = function (sourceFile) {
43 return sourceFile.languageVariant === ts.LanguageVariant.JSX ? this.applyWithFunction(sourceFile, walk) : [];
44 };
45 Rule.metadata = {
46 ruleName: 'react-a11y-role-supports-aria-props',
47 type: 'maintainability',
48 description: 'Enforce that elements with explicit or implicit roles defined contain only `aria-*` properties supported by that `role`. ' +
49 'Many aria attributes (states and properties) can only be used on elements with particular roles. ' +
50 "Some elements have implicit roles, such as `<a href='hrefValue' />`, which will be resolved to `role='link'`. " +
51 'A reference for the implicit roles can be found at [Default Implicit ARIA Semantics](https://www.w3.org/TR/html-aria/#sec-strong-native-semantics).',
52 rationale: "References:\n <ul>\n <li><a href=\"http://oaa-accessibility.org/wcag20/rule/87\">ARIA attributes can only be used with certain roles</a></li>\n <li><a href=\"http://oaa-accessibility.org/wcag20/rule/84\">Check aria properties and states for valid roles and properties</a></li>\n <li><a href=\"http://oaa-accessibility.org/wcag20/rule/93\">Check that 'ARIA-' attributes are valid properties and states</a></li>\n </ul>",
53 options: null,
54 optionsDescription: '',
55 typescriptOnly: true,
56 issueClass: 'Non-SDL',
57 issueType: 'Warning',
58 severity: 'Important',
59 level: 'Opportunity for Excellence',
60 group: 'Accessibility'
61 };
62 return Rule;
63}(Lint.Rules.AbstractRule));
64exports.Rule = Rule;
65function walk(ctx) {
66 function checkJsxElement(node) {
67 var attributesInElement = JsxAttribute_1.getJsxAttributesFromJsxElement(node);
68 var roleProp = attributesInElement[ROLE_STRING];
69 var roleValue;
70 if (node.tagName.getText().match(/^[A-Z].*/)) {
71 return;
72 }
73 if (roleProp !== undefined) {
74 roleValue = JsxAttribute_1.getStringLiteral(roleProp);
75 if (!JsxAttribute_1.isEmpty(roleProp) && roleValue === undefined) {
76 return;
77 }
78 }
79 else {
80 roleValue = getImplicitRole_1.getImplicitRole(node);
81 }
82 var isImplicitRole = !roleProp && !!roleValue;
83 var normalizedRoles = (roleValue || '')
84 .toLowerCase()
85 .split(' ')
86 .filter(function (role) { return role in ROLES; });
87 var supportedAttributeNames = ROLE_SCHEMA.globalSupportedProps;
88 normalizedRoles.forEach(function (role) {
89 supportedAttributeNames = supportedAttributeNames.concat(ROLES[role].additionalSupportedProps || []);
90 });
91 var attributeNamesInElement = Object.keys(attributesInElement).filter(function (attributeName) { return !!ARIA_ATTRIBUTES[attributeName.toLowerCase()]; });
92 var invalidAttributeNamesInElement = attributeNamesInElement.filter(function (attributeName) { return supportedAttributeNames.indexOf(attributeName) === -1; });
93 var failureString;
94 if (normalizedRoles.length === 0) {
95 failureString = getFailureStringForNoRole(node.tagName.getText(), invalidAttributeNamesInElement);
96 }
97 else if (isImplicitRole) {
98 failureString = getFailureStringForImplicitRole(node.tagName.getText(), normalizedRoles[0], invalidAttributeNamesInElement);
99 }
100 else {
101 failureString = getFailureStringForNotImplicitRole(normalizedRoles, invalidAttributeNamesInElement);
102 }
103 if (invalidAttributeNamesInElement.length > 0) {
104 ctx.addFailureAt(node.getStart(), node.getWidth(), failureString);
105 }
106 }
107 function cb(node) {
108 if (tsutils.isJsxElement(node)) {
109 checkJsxElement(node.openingElement);
110 }
111 else if (tsutils.isJsxSelfClosingElement(node)) {
112 checkJsxElement(node);
113 }
114 return ts.forEachChild(node, cb);
115 }
116 return ts.forEachChild(ctx.sourceFile, cb);
117}
118//# sourceMappingURL=reactA11yRoleSupportsAriaPropsRule.js.map
\No newline at end of file