UNPKG

@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
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;