@jsxtools/eslint-plugin-jsx-a11y
Version:
Static AST checker for accessibility rules on JSX elements for flat ESLint Config.
87 lines (84 loc) • 3.19 kB
JavaScript
const ariaQuery = require('aria-query');
const jsxAstUtils = require('../util/module/jsx-ast-utils.cjs');
const schemas = require('../util/schemas.cjs');
const errorMessage = (name, type, permittedValues) => {
switch (type) {
case "tristate":
return `The value for ${name} must be a boolean or the string "mixed".`;
case "token":
return `The value for ${name} must be a single token from the following: ${permittedValues}.`;
case "tokenlist":
return `The value for ${name} must be a list of one or more tokens from the following: ${permittedValues}.`;
case "idlist":
return `The value for ${name} must be a list of strings that represent DOM element IDs (idlist)`;
case "id":
return `The value for ${name} must be a string that represents a DOM element ID`;
case "boolean":
case "string":
case "integer":
case "number":
default:
return `The value for ${name} must be a ${type}.`;
}
};
const validityCheck = (value, expectedType, permittedValues) => {
switch (expectedType) {
case "boolean":
return typeof value === "boolean";
case "string":
case "id":
return typeof value === "string";
case "tristate":
return typeof value === "boolean" || value === "mixed";
case "integer":
case "number":
return typeof value !== "boolean" && isNaN(Number(value)) === false;
case "token":
return permittedValues.indexOf(typeof value === "string" ? value.toLowerCase() : value) > -1;
case "idlist":
return typeof value === "string" && value.split(" ").every((token) => validityCheck(token, "id", []));
case "tokenlist":
return typeof value === "string" && value.split(" ").every((token) => permittedValues.indexOf(token.toLowerCase()) > -1);
default:
return false;
}
};
const schema = schemas.generateObjSchema();
const ruleOfAriaProptypes = {
validityCheck,
meta: {
docs: {
url: "https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-proptypes.md",
description: "Enforce ARIA state and property values are valid."
},
schema: [schema]
},
create: (context) => ({
JSXAttribute: (attribute) => {
const name = jsxAstUtils.propName(attribute);
const normalizedName = name.toLowerCase();
if (normalizedName.indexOf("aria-") !== 0 || ariaQuery.aria.get(normalizedName) === void 0) {
return;
}
if (jsxAstUtils.getPropValue(attribute) == null)
return;
const value = jsxAstUtils.getLiteralPropValue(attribute);
if (value === null) {
return;
}
const attributes = ariaQuery.aria.get(normalizedName);
const permittedType = attributes.type;
const allowUndefined = attributes.allowUndefined || false;
const permittedValues = attributes.values || [];
const isValid = validityCheck(value, permittedType, permittedValues) || allowUndefined && value === void 0;
if (isValid) {
return;
}
context.report({
node: attribute,
message: errorMessage(name, permittedType, permittedValues)
});
}
})
};
module.exports = ruleOfAriaProptypes;