UNPKG

8.71 kBJavaScriptView Raw
1"use strict";
2var __extends = (this && this.__extends) || (function () {
3 var extendStatics = Object.setPrototypeOf ||
4 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6 return function (d, b) {
7 extendStatics(d, b);
8 function __() { this.constructor = d; }
9 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
10 };
11})();
12Object.defineProperty(exports, "__esModule", { value: true });
13var ts = require("typescript");
14var Lint = require("tslint");
15var AstUtils_1 = require("./utils/AstUtils");
16var JsxAttribute_1 = require("./utils/JsxAttribute");
17var TypeGuard_1 = require("./utils/TypeGuard");
18var aria = require('./utils/attributes/ariaSchema.json');
19function getFailureString(propName, expectedType, permittedValues) {
20 switch (expectedType) {
21 case 'tristate':
22 return "The value for " + propName + " must be a boolean or the string 'mixed'.";
23 case 'token':
24 return "The value for " + propName + " must be a single token from the following: " + permittedValues + ".";
25 case 'tokenlist':
26 return "The value for " + propName + " must be a list of one or more tokens from the following: " + permittedValues + ".";
27 case 'boolean':
28 case 'string':
29 case 'integer':
30 case 'number':
31 default:
32 return "The value for " + propName + " must be a " + expectedType + ".";
33 }
34}
35exports.getFailureString = getFailureString;
36var Rule = (function (_super) {
37 __extends(Rule, _super);
38 function Rule() {
39 return _super !== null && _super.apply(this, arguments) || this;
40 }
41 Rule.prototype.apply = function (sourceFile) {
42 return sourceFile.languageVariant === ts.LanguageVariant.JSX
43 ? this.applyWithWalker(new ReactA11yProptypesWalker(sourceFile, this.getOptions()))
44 : [];
45 };
46 Rule.metadata = {
47 ruleName: 'react-a11y-proptypes',
48 type: 'maintainability',
49 description: 'Enforce ARIA state and property values are valid.',
50 options: null,
51 optionsDescription: '',
52 typescriptOnly: true,
53 issueClass: 'Non-SDL',
54 issueType: 'Warning',
55 severity: 'Important',
56 level: 'Opportunity for Excellence',
57 group: 'Accessibility'
58 };
59 return Rule;
60}(Lint.Rules.AbstractRule));
61exports.Rule = Rule;
62var ReactA11yProptypesWalker = (function (_super) {
63 __extends(ReactA11yProptypesWalker, _super);
64 function ReactA11yProptypesWalker() {
65 return _super !== null && _super.apply(this, arguments) || this;
66 }
67 ReactA11yProptypesWalker.prototype.visitJsxAttribute = function (node) {
68 var propName = JsxAttribute_1.getPropName(node).toLowerCase();
69 if (!aria[propName]) {
70 return;
71 }
72 var allowUndefined = aria[propName].allowUndefined != null
73 ? aria[propName].allowUndefined
74 : false;
75 var expectedType = aria[propName].type;
76 var permittedValues = aria[propName].values;
77 var propValue = JsxAttribute_1.getStringLiteral(node) || String(JsxAttribute_1.getBooleanLiteral(node));
78 if (this.isUndefined(node.initializer)) {
79 if (!allowUndefined) {
80 this.addFailureAt(node.getStart(), node.getWidth(), getFailureString(propName, expectedType, permittedValues));
81 }
82 return;
83 }
84 else if (this.isComplexType(node.initializer)) {
85 return;
86 }
87 if (!this.validityCheck(node.initializer, propValue, expectedType, permittedValues)) {
88 this.addFailureAt(node.getStart(), node.getWidth(), getFailureString(propName, expectedType, permittedValues));
89 }
90 };
91 ReactA11yProptypesWalker.prototype.validityCheck = function (propValueExpression, propValue, expectedType, permittedValues) {
92 switch (expectedType) {
93 case 'boolean': return this.isBoolean(propValueExpression);
94 case 'tristate': return this.isBoolean(propValueExpression) || this.isMixed(propValueExpression);
95 case 'integer': return this.isInteger(propValueExpression);
96 case 'number': return this.isNumber(propValueExpression);
97 case 'string': return this.isString(propValueExpression);
98 case 'token':
99 return (this.isString(propValueExpression) || this.isBoolean(propValueExpression)) &&
100 permittedValues.indexOf(propValue.toLowerCase()) > -1;
101 case 'tokenlist':
102 return (this.isString(propValueExpression) || this.isBoolean(propValueExpression)) &&
103 propValue.split(' ').every(function (token) { return permittedValues.indexOf(token.toLowerCase()) > -1; });
104 default:
105 return false;
106 }
107 };
108 ReactA11yProptypesWalker.prototype.isUndefined = function (node) {
109 if (!node) {
110 return true;
111 }
112 else if (TypeGuard_1.isJsxExpression(node)) {
113 var expression = node.expression;
114 if (!expression) {
115 return true;
116 }
117 else if (AstUtils_1.AstUtils.isUndefined(expression)) {
118 return true;
119 }
120 else if (TypeGuard_1.isNullKeyword(expression)) {
121 return true;
122 }
123 }
124 return false;
125 };
126 ReactA11yProptypesWalker.prototype.isComplexType = function (node) {
127 return !this.isUndefined(node) && TypeGuard_1.isJsxExpression(node) && !AstUtils_1.AstUtils.isConstant(node.expression);
128 };
129 ReactA11yProptypesWalker.prototype.isBoolean = function (node) {
130 if (TypeGuard_1.isStringLiteral(node)) {
131 var propValue = node.text.toLowerCase();
132 return propValue === 'true' || propValue === 'false';
133 }
134 else if (TypeGuard_1.isJsxExpression(node)) {
135 var expression = node.expression;
136 if (TypeGuard_1.isStringLiteral(expression)) {
137 var propValue = expression.text.toLowerCase();
138 return propValue === 'true' || propValue === 'false';
139 }
140 else {
141 return TypeGuard_1.isFalseKeyword(expression) || TypeGuard_1.isTrueKeyword(expression);
142 }
143 }
144 return false;
145 };
146 ReactA11yProptypesWalker.prototype.isMixed = function (node) {
147 if (TypeGuard_1.isStringLiteral(node)) {
148 return node.text.toLowerCase() === 'mixed';
149 }
150 else if (TypeGuard_1.isJsxExpression(node)) {
151 var expression = node.expression;
152 return TypeGuard_1.isStringLiteral(expression) && expression.text.toLowerCase() === 'mixed';
153 }
154 return false;
155 };
156 ReactA11yProptypesWalker.prototype.isNumber = function (node) {
157 if (TypeGuard_1.isStringLiteral(node)) {
158 return !isNaN(Number(node.text));
159 }
160 else if (TypeGuard_1.isJsxExpression(node)) {
161 var expression = node.expression;
162 if (TypeGuard_1.isStringLiteral(expression)) {
163 return !isNaN(Number(expression.text));
164 }
165 else {
166 return TypeGuard_1.isNumericLiteral(expression);
167 }
168 }
169 return false;
170 };
171 ReactA11yProptypesWalker.prototype.isInteger = function (node) {
172 if (TypeGuard_1.isStringLiteral(node)) {
173 var value = Number(node.text);
174 return !isNaN(value) && Math.round(value) === value;
175 }
176 else if (TypeGuard_1.isJsxExpression(node)) {
177 var expression = node.expression;
178 if (TypeGuard_1.isStringLiteral(expression)) {
179 var value = Number(expression.text);
180 return !isNaN(value) && Math.round(value) === value;
181 }
182 else if (TypeGuard_1.isNumericLiteral(expression)) {
183 var value = Number(expression.text);
184 return Math.round(value) === value;
185 }
186 return false;
187 }
188 return false;
189 };
190 ReactA11yProptypesWalker.prototype.isString = function (node) {
191 return TypeGuard_1.isStringLiteral(node) || (TypeGuard_1.isJsxExpression(node) && TypeGuard_1.isStringLiteral(node.expression));
192 };
193 return ReactA11yProptypesWalker;
194}(Lint.RuleWalker));
195//# sourceMappingURL=reactA11yProptypesRule.js.map
\No newline at end of file