UNPKG

@atlaskit/eslint-plugin-design-system

Version:

The essential plugin for use with the Atlassian Design System.

87 lines 4.26 kB
import { isNodeOfType } from 'eslint-codemod-utils'; import { createLintRule } from '../utils/create-lint-rule'; var elementsAccessibleNameProps = ['label', 'titleId', 'heading']; var rule = createLintRule({ meta: { name: 'use-onboarding-spotlight-label', type: 'suggestion', docs: { description: 'Ensures onboarding spotlight dialogs are described to assistive technology by a direct label or by another element.', recommended: true, severity: 'warn' }, messages: { missingAccessibleName: 'Missing accessible name. Either specify `heading` or if there is a requirement to reference another element in the DOM as accessible name, use `titleId`. Otherwise, use `label` to explicitly provide the accessible name.', labelPropShouldHaveContent: 'The Spotlight component requires a non-empty label.', headingPropShouldHaveContent: 'The Spotlight component requires a non-empty heading.', titleIdShouldHaveValue: '`titleId` should reference the id of the element that defines accessible name.', noCombinedPropsUsage: 'Avoid using `heading`, `titleId` and `label` properties simultaneously. If the `heading` value is not specified or there is a requirement to reference another element in the DOM as accessible name, use `titleId`. Otherwise, use `label` to explicitly provide the accessible name.' }, hasSuggestions: true }, create: function create(context) { var contextLocalIdentifier = []; return { ImportDeclaration: function ImportDeclaration(node) { var _node$specifiers; var buttonGroupIdentifier = (_node$specifiers = node.specifiers) === null || _node$specifiers === void 0 ? void 0 : _node$specifiers.filter(function (spec) { if (node.source.value === '@atlaskit/onboarding') { var _spec$imported; return spec.type === 'ImportSpecifier' && 'name' in spec.imported && ((_spec$imported = spec.imported) === null || _spec$imported === void 0 ? void 0 : _spec$imported.name) === 'Spotlight'; } if (node.source.value === '@atlaskit/onboarding/spotlight') { return spec.type === 'ImportDefaultSpecifier'; } }); if (buttonGroupIdentifier !== null && buttonGroupIdentifier !== void 0 && buttonGroupIdentifier.length) { var local = buttonGroupIdentifier[0].local; contextLocalIdentifier.push(local.name); } }, JSXElement: function JSXElement(node) { if (!isNodeOfType(node, 'JSXElement')) { return; } if (!isNodeOfType(node.openingElement.name, 'JSXIdentifier')) { return; } var name = node.openingElement.name.name; if (contextLocalIdentifier.includes(name)) { var componentLabelProps = node.openingElement.attributes.filter(function (attr) { return isNodeOfType(attr, 'JSXAttribute') && isNodeOfType(attr.name, 'JSXIdentifier') && elementsAccessibleNameProps.includes(attr.name.name); }); if (componentLabelProps.length === 1) { var prop = componentLabelProps[0]; if ('value' in prop && prop.value) { if (isNodeOfType(prop.value, 'Literal') && !prop.value.value || isNodeOfType(prop.value, 'JSXExpressionContainer') && !prop.value.expression) { context.report({ node: prop, messageId: function () { if (prop.name.name === 'label') { return 'labelPropShouldHaveContent'; } else if (prop.name.name === 'titleId') { return 'titleIdShouldHaveValue'; } else { return 'headingPropShouldHaveContent'; } }() }); } } } else if (componentLabelProps.length > 1) { context.report({ node: node.openingElement, messageId: 'noCombinedPropsUsage' }); } else { context.report({ node: node.openingElement, messageId: 'missingAccessibleName' }); } } } }; } }); export default rule;