diff --git a/dist/lib/index.js b/dist/lib/index.js index f2493d3..e1784d5 100644 --- a/dist/lib/index.js +++ b/dist/lib/index.js @@ -7,6 +7,32 @@ var __importDefault = (this && this.__importDefault) || function (mod) { Object.defineProperty(exports, "__esModule", { value: true }); console.log("Loading my-eslint-plugin"); const prefer_aria_over_title_attribute_1 = __importDefault(require("./rules/prefer-aria-over-title-attribute")); +const checkbox_needs_labelling_1 = __importDefault(require("./rules/checkbox-needs-labelling")); +const image_button_missing_aria_1 = __importDefault(require("./rules/buttons/image-button-missing-aria")); +const link_missing_labelling_1 = __importDefault(require("./rules/link-missing-labelling")); +const input_components_require_accessible_name_1 = __importDefault(require("./rules/input-components-require-accessible-name")); +const menu_item_needs_labelling_1 = __importDefault(require("./rules/menu-item-needs-labelling")); +const switch_needs_labelling_1 = __importDefault(require("./rules/switch-needs-labelling")); +const toolbar_missing_aria_1 = __importDefault(require("./rules/toolbar-missing-aria")); +const combobox_needs_labelling_1 = __importDefault(require("./rules/combobox-needs-labelling")); +const no_empty_components_1 = __importDefault(require("./rules/no-empty-components")); +const accordion_header_needs_labelling_1 = __importDefault(require("./rules/accordion-header-needs-labelling")); +const accordion_item_needs_header_and_panel_1 = __importDefault(require("./rules/accordion-item-needs-header-and-panel")); +const compound_button_needs_labelling_1 = __importDefault(require("./rules/buttons/compound-button-needs-labelling")); +const no_empty_buttons_1 = __importDefault(require("./rules/buttons/no-empty-buttons")); +const spin_button_needs_labelling_1 = __importDefault(require("./rules/spin-button-needs-labelling")); +const spin_button_unrecommended_labelling_1 = __importDefault(require("./rules/spin-button-unrecommended-labelling")); +const breadcrumb_needs_labelling_1 = __importDefault(require("./rules/breadcrumb-needs-labelling")); +const dropdown_needs_labelling_1 = __importDefault(require("./rules/dropdown-needs-labelling")); +const tooltip_not_recommended_1 = __importDefault(require("./rules/tooltip-not-recommended")); +const avatar_needs_name_1 = __importDefault(require("./rules/avatar-needs-name")); +const radio_button_missing_label_1 = __importDefault(require("./rules/radio-button-missing-label")); +const radiogroup_missing_label_1 = __importDefault(require("./rules/radiogroup-missing-label")); +const dialogbody_needs_title_content_and_actions_1 = __importDefault(require("./rules/dialogbody-needs-title-content-and-actions")); +const dialogsurface_needs_aria_1 = __importDefault(require("./rules/dialogsurface-needs-aria")); +const spinner_needs_labelling_1 = __importDefault(require("./rules/spinner-needs-labelling")); +const badge_needs_accessible_name_1 = __importDefault(require("./rules/badge-needs-accessible-name")); +const progressbar_needs_labelling_1 = __importDefault(require("./rules/progressbar-needs-labelling")); const field_needs_labelling_1 = __importDefault(require("./rules/field-needs-labelling")); //------------------------------------------------------------------------------ // Requirements @@ -17,33 +43,33 @@ const field_needs_labelling_1 = __importDefault(require("./rules/field-needs-lab // import all rules in lib/rules module.exports = { rules: { - "checkbox-needs-labelling": require("./rules/checkbox-needs-labelling"), - "image-button-missing-aria": require("./rules/buttons/image-button-missing-aria"), - "link-missing-labelling": require("./rules/link-missing-labelling"), - "input-components-require-accessible-name": require("./rules/input-components-require-accessible-name"), - "menu-item-needs-labelling": require("./rules/menu-item-needs-labelling"), - "switch-needs-labelling": require("./rules/switch-needs-labelling"), - "toolbar-missing-aria": require("./rules/toolbar-missing-aria"), - "combobox-needs-labelling": require("./rules/combobox-needs-labelling"), - "no-empty-components": require("./rules/no-empty-components"), - "accordion-header-needs-labelling": require("./rules/accordion-header-needs-labelling"), - "accordion-item-needs-header-and-panel": require("./rules/accordion-item-needs-header-and-panel"), - "compound-button-needs-labelling": require("./rules/buttons/compound-button-needs-labelling"), - "no-empty-buttons": require("./rules/buttons/no-empty-buttons"), - "spin-button-needs-labelling": require("./rules/spin-button-needs-labelling"), - "spin-button-unrecommended-labelling": require("./rules/spin-button-unrecommended-labelling"), - "breadcrumb-needs-labelling": require("./rules/breadcrumb-needs-labelling"), - "dropdown-needs-labelling": require("./rules/dropdown-needs-labelling"), - "tooltip-not-recommended": require("./rules/tooltip-not-recommended"), - "avatar-needs-name": require("./rules/avatar-needs-name"), - "radio-button-missing-label": require("./rules/radio-button-missing-label"), - "radiogroup-missing-label": require("./rules/radiogroup-missing-label"), + "checkbox-needs-labelling": checkbox_needs_labelling_1.default, + "image-button-missing-aria": image_button_missing_aria_1.default, + "link-missing-labelling": link_missing_labelling_1.default, + "input-components-require-accessible-name": input_components_require_accessible_name_1.default, + "menu-item-needs-labelling": menu_item_needs_labelling_1.default, + "switch-needs-labelling": switch_needs_labelling_1.default, + "toolbar-missing-aria": toolbar_missing_aria_1.default, + "combobox-needs-labelling": combobox_needs_labelling_1.default, + "no-empty-components": no_empty_components_1.default, + "accordion-header-needs-labelling": accordion_header_needs_labelling_1.default, + "accordion-item-needs-header-and-panel": accordion_item_needs_header_and_panel_1.default, + "compound-button-needs-labelling": compound_button_needs_labelling_1.default, + "no-empty-buttons": no_empty_buttons_1.default, + "spin-button-needs-labelling": spin_button_needs_labelling_1.default, + "spin-button-unrecommended-labelling": spin_button_unrecommended_labelling_1.default, + "breadcrumb-needs-labelling": breadcrumb_needs_labelling_1.default, + "dropdown-needs-labelling": dropdown_needs_labelling_1.default, + "tooltip-not-recommended": tooltip_not_recommended_1.default, + "avatar-needs-name": avatar_needs_name_1.default, + "radio-button-missing-label": radio_button_missing_label_1.default, + "radiogroup-missing-label": radiogroup_missing_label_1.default, "prefer-aria-over-title-attribute": prefer_aria_over_title_attribute_1.default, - "dialogbody-needs-title-content-and-actions": require("./rules/dialogbody-needs-title-content-and-actions"), - "dialogsurface-needs-aria": require("./rules/dialogsurface-needs-aria"), - "spinner-needs-labelling": require("./rules/spinner-needs-labelling"), - "badge-needs-accessible-name": require("./rules/badge-needs-accessible-name"), - "progressbar-needs-labelling": require("./rules/progressbar-needs-labelling"), + "dialogbody-needs-title-content-and-actions": dialogbody_needs_title_content_and_actions_1.default, + "dialogsurface-needs-aria": dialogsurface_needs_aria_1.default, + "spinner-needs-labelling": spinner_needs_labelling_1.default, + "badge-needs-accessible-name": badge_needs_accessible_name_1.default, + "progressbar-needs-labelling": progressbar_needs_labelling_1.default, "field-needs-labelling": field_needs_labelling_1.default }, configs: { diff --git a/dist/lib/rules/accordion-header-needs-labelling.d.ts b/dist/lib/rules/accordion-header-needs-labelling.d.ts index de4c0ec..f2a0058 100644 --- a/dist/lib/rules/accordion-header-needs-labelling.d.ts +++ b/dist/lib/rules/accordion-header-needs-labelling.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingAriaLabel", [], { + JSXElement(node: TSESTree.JSXElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/accordion-header-needs-labelling.js b/dist/lib/rules/accordion-header-needs-labelling.js index f3b0a88..ccb655e 100644 --- a/dist/lib/rules/accordion-header-needs-labelling.js +++ b/dist/lib/rules/accordion-header-needs-labelling.js @@ -1,17 +1,18 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const { hasToolTipParent } = require("../util/hasTooltipParent"); -const { hasTextContentChild } = require("../util/hasTextContentChild"); -const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); -var hasProp = require("jsx-ast-utils").hasProp; -var elementType = require("jsx-ast-utils").elementType; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const hasTooltipParent_1 = require("../util/hasTooltipParent"); +const hasTextContentChild_1 = require("../util/hasTextContentChild"); +const labelUtils_1 = require("../util/labelUtils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { messages: { missingAriaLabel: "Accessibility: the accordion header must have an accessible name" @@ -19,10 +20,8 @@ module.exports = { type: "problem", // `problem`, `suggestion`, or `layout` docs: { description: "The accordion header is a button and it needs an accessibile name e.g. text content, aria-label, aria-labelledby.", - recommended: false, - url: null // URL to the documentation page for this rule + recommended: false }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, // create (function) returns an object with methods that ESLint calls to “visit” nodes while traversing the abstract syntax tree @@ -32,26 +31,27 @@ module.exports = { JSXElement(node) { const openingElement = node.openingElement; // if it is not a AccordionHeader, return - if (elementType(openingElement) !== "AccordionHeader") { + if ((0, jsx_ast_utils_1.elementType)(openingElement) !== "AccordionHeader") { return; } // if it has text content, return - if (hasTextContentChild(node)) { + if ((0, hasTextContentChild_1.hasTextContentChild)(node)) { return; } // if it is not an icon button, return - if (!hasProp(openingElement.attributes, "icon") && !hasProp(openingElement.attributes, "expandIcon")) { + if (!(0, jsx_ast_utils_1.hasProp)(openingElement.attributes, "icon") && + !(0, jsx_ast_utils_1.hasProp)(openingElement.attributes, "expandIcon")) { return; } // if it has a tooltip parent, return - if (hasToolTipParent(context)) { + if ((0, hasTooltipParent_1.hasToolTipParent)(context)) { return; } // the button has an associated label - if (hasAssociatedLabelViaAriaLabelledBy(openingElement, context)) { + if ((0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(openingElement, context)) { return; } - const hasAccessibleLabelling = hasNonEmptyProp(openingElement.attributes, "title") || hasNonEmptyProp(openingElement.attributes, "aria-label"); + const hasAccessibleLabelling = (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "title") || (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "aria-label"); // if it has no accessible name, report error if (!hasAccessibleLabelling) { context.report({ @@ -62,4 +62,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/accordion-item-needs-header-and-panel.d.ts b/dist/lib/rules/accordion-item-needs-header-and-panel.d.ts index de4c0ec..34313bb 100644 --- a/dist/lib/rules/accordion-item-needs-header-and-panel.d.ts +++ b/dist/lib/rules/accordion-item-needs-header-and-panel.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"accordionItemOneHeaderOnePanel", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/accordion-item-needs-header-and-panel.js b/dist/lib/rules/accordion-item-needs-header-and-panel.js index 6dc0f8d..d25ab92 100644 --- a/dist/lib/rules/accordion-item-needs-header-and-panel.js +++ b/dist/lib/rules/accordion-item-needs-header-and-panel.js @@ -1,11 +1,13 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { messages: { accordionItemOneHeaderOnePanel: "ensure AccordionItem has exactly one header and one panel" @@ -13,21 +15,25 @@ module.exports = { type: "problem", // `problem`, `suggestion`, or `layout` docs: { description: "An AccordionItem needs exactly one header and one panel", - recommended: true, + recommended: "strict", url: "https://www.w3.org/WAI/ARIA/apg/patterns/accordion/" // URL to the documentation page for this rule }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, create(context) { return { JSXOpeningElement(node) { - if (node.name.name !== "AccordionItem") { + if (node.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier && node.name.name !== "AccordionItem") { + return; + } + if (!(node.parent && node.parent.type === utils_1.AST_NODE_TYPES.JSXElement)) { return; } const children = node.parent.children.filter(child => child.type === "JSXElement"); - const hasOneHeader = children.filter(child => child.openingElement.name.name === "AccordionHeader").length === 1; - const hasOnePanel = children.filter(child => child.openingElement.name.name === "AccordionPanel").length === 1; + const hasOneHeader = children.filter(child => child.openingElement.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "AccordionHeader").length === 1; + const hasOnePanel = children.filter(child => child.openingElement.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "AccordionPanel").length === 1; if (!hasOneHeader || !hasOnePanel || children.length !== 2) { context.report({ node, @@ -37,4 +43,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/avatar-needs-name.d.ts b/dist/lib/rules/avatar-needs-name.d.ts index 1bb0b91..3ac584a 100644 --- a/dist/lib/rules/avatar-needs-name.d.ts +++ b/dist/lib/rules/avatar-needs-name.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let missingAriaLabel: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXOpeningElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingAriaLabel", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/avatar-needs-name.js b/dist/lib/rules/avatar-needs-name.js index fc133e3..79adb20 100644 --- a/dist/lib/rules/avatar-needs-name.js +++ b/dist/lib/rules/avatar-needs-name.js @@ -1,13 +1,16 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const labelUtils_1 = require("../util/labelUtils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -19,7 +22,7 @@ module.exports = { docs: { // DONE description: "Accessibility: Avatar must have an accessible labelling: name, aria-label, aria-labelledby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -30,13 +33,13 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not an Avatar, return - if (elementType(node) !== "Avatar") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "Avatar") { return; } // if the Avatar has a name, aria-label or aria-labelledby, return - if (hasNonEmptyProp(node.attributes, "name") || - hasNonEmptyProp(node.attributes, "aria-label") || - hasAssociatedLabelViaAriaLabelledBy(node, context)) { + if ((0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "name") || + (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-label") || + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(node, context)) { return; } // no aria @@ -47,4 +50,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/avoid-using-aria-describedby-for-primary-labelling.d.ts b/dist/lib/rules/avoid-using-aria-describedby-for-primary-labelling.d.ts index de4c0ec..ae2e6fb 100644 --- a/dist/lib/rules/avoid-using-aria-describedby-for-primary-labelling.d.ts +++ b/dist/lib/rules/avoid-using-aria-describedby-for-primary-labelling.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noAriaDescribedbyAsLabel", [], { + JSXElement(node: TSESTree.JSXElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/avoid-using-aria-describedby-for-primary-labelling.js b/dist/lib/rules/avoid-using-aria-describedby-for-primary-labelling.js index 702d7e5..be3887a 100644 --- a/dist/lib/rules/avoid-using-aria-describedby-for-primary-labelling.js +++ b/dist/lib/rules/avoid-using-aria-describedby-for-primary-labelling.js @@ -1,19 +1,21 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { applicableComponents: inputComponents } = require("../applicableComponents/inputBasedComponents"); -const { applicableComponents: buttonComponents } = require("../applicableComponents/buttonBasedComponents"); -const { elementType } = require("jsx-ast-utils"); -const { isInsideLabelTag, hasAssociatedLabelViaHtmlFor, hasAssociatedLabelViaAriaLabelledBy, hasAssociatedLabelViaAriaDescribedby } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const { hasToolTipParent } = require("../util/hasTooltipParent"); -const { hasTextContentChild } = require("../util/hasTextContentChild"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const inputBasedComponents_1 = require("../applicableComponents/inputBasedComponents"); +const buttonBasedComponents_1 = require("../applicableComponents/buttonBasedComponents"); +const labelUtils_1 = require("../util/labelUtils"); +const hasFieldParent_1 = require("../util/hasFieldParent"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const hasTooltipParent_1 = require("../util/hasTooltipParent"); +const hasTextContentChild_1 = require("../util/hasTextContentChild"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { messages: { noAriaDescribedbyAsLabel: "Accessibility: aria-describedby provides additional context and is not meant for primary labeling." @@ -21,35 +23,33 @@ module.exports = { type: "suggestion", // `problem`, `suggestion`, or `layout` docs: { description: "aria-describedby provides additional context and is not meant for primary labeling.", - recommended: true, - url: null // URL to the documentation page for this rule + recommended: "strict" }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, create(context) { return { JSXElement(node) { const openingElement = node.openingElement; - if (buttonComponents.includes(elementType(openingElement)) && // It's a button-based component - !hasToolTipParent(context) && // It doesn't have a tooltip parent - !hasTextContentChild(node) && // It doesn't have text content - !hasNonEmptyProp(openingElement.attributes, "title") && // Doesn't have a title - !hasNonEmptyProp(openingElement.attributes, "aria-label") && // Doesn't have an aria-label - !hasAssociatedLabelViaAriaLabelledBy(openingElement, context) && // Doesn't have aria-labelledby - hasAssociatedLabelViaAriaDescribedby(openingElement, context) // But it does have aria-describedby + if (buttonBasedComponents_1.applicableComponents.includes((0, jsx_ast_utils_1.elementType)(openingElement)) && // It's a button-based component + !(0, hasTooltipParent_1.hasToolTipParent)(context) && // It doesn't have a tooltip parent + !(0, hasTextContentChild_1.hasTextContentChild)(node) && // It doesn't have text content + !(0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "title") && // Doesn't have a title + !(0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "aria-label") && // Doesn't have an aria-label + !(0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(openingElement, context) && // Doesn't have aria-labelledby + (0, labelUtils_1.hasAssociatedLabelViaAriaDescribedby)(openingElement, context) // But it does have aria-describedby ) { context.report({ node, messageId: "noAriaDescribedbyAsLabel" }); } - if (inputComponents.includes(elementType(openingElement)) && // It's an input component - !hasFieldParent(context) && // It doesn't have a field parent - !isInsideLabelTag(context) && // It's not inside a label tag - !hasAssociatedLabelViaHtmlFor(openingElement, context) && // Doesn't have a label via htmlFor - !hasAssociatedLabelViaAriaLabelledBy(openingElement, context) && // Doesn't have aria-labelledby - hasAssociatedLabelViaAriaDescribedby(openingElement, context) // But it does have aria-describedby + if (inputBasedComponents_1.applicableComponents.includes((0, jsx_ast_utils_1.elementType)(openingElement)) && // It's an input component + !(0, hasFieldParent_1.hasFieldParent)(context) && // It doesn't have a field parent + !(0, labelUtils_1.isInsideLabelTag)(context) && // It's not inside a label tag + !(0, labelUtils_1.hasAssociatedLabelViaHtmlFor)(openingElement, context) && // Doesn't have a label via htmlFor + !(0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(openingElement, context) && // Doesn't have aria-labelledby + (0, labelUtils_1.hasAssociatedLabelViaAriaDescribedby)(openingElement, context) // But it does have aria-describedby ) { context.report({ node, @@ -59,4 +59,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/badge-needs-accessible-name.d.ts b/dist/lib/rules/badge-needs-accessible-name.d.ts index de4c0ec..50c63b5 100644 --- a/dist/lib/rules/badge-needs-accessible-name.d.ts +++ b/dist/lib/rules/badge-needs-accessible-name.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"badgeNeedsAccessibleName" | "colourOnlyBadgesNeedAttributes" | "badgeIconNeedsLabelling", [], { + JSXElement(node: TSESTree.JSXElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/badge-needs-accessible-name.js b/dist/lib/rules/badge-needs-accessible-name.js index 06b1dad..4ab3b3e 100644 --- a/dist/lib/rules/badge-needs-accessible-name.js +++ b/dist/lib/rules/badge-needs-accessible-name.js @@ -1,15 +1,16 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -var elementType = require("jsx-ast-utils").elementType; -const { getPropValue, getProp } = require("jsx-ast-utils"); -const { hasTextContentChild } = require("../util/hasTextContentChild"); -var hasProp = require("jsx-ast-utils").hasProp; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const jsx_ast_utils_2 = require("jsx-ast-utils"); +const hasTextContentChild_1 = require("../util/hasTextContentChild"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -32,22 +33,22 @@ module.exports = { JSXElement(node) { const openingElement = node.openingElement; // If it's not a Badge component, return early - if (elementType(openingElement) !== "Badge") { + if ((0, jsx_ast_utils_1.elementType)(openingElement) !== "Badge") { return; } - const hasTextContent = hasTextContentChild(node); + const hasTextContent = (0, hasTextContentChild_1.hasTextContentChild)(node); // Check if Badge has text content and return early if it does if (hasTextContent) { return; } // Check if Badge has an icon - const hasIconProp = hasProp(openingElement.attributes, "icon"); + const hasIconProp = (0, jsx_ast_utils_1.hasProp)(openingElement.attributes, "icon"); if (hasIconProp) { - const iconProp = getProp(openingElement.attributes, "icon"); - if (iconProp) { + const iconProp = (0, jsx_ast_utils_2.getProp)(openingElement.attributes, "icon"); + if (iconProp && iconProp.value && iconProp.value.type === utils_1.AST_NODE_TYPES.JSXExpressionContainer) { const iconElement = iconProp.value.expression; // Check if the icon has an aria-label - const ariaLabelAttr = hasProp(iconElement.openingElement.attributes, "aria-label"); + const ariaLabelAttr = (0, jsx_ast_utils_1.hasProp)(iconElement.openingElement.attributes, "aria-label"); // Report an error if aria-label is missing if (!ariaLabelAttr) { context.report({ @@ -62,9 +63,10 @@ module.exports = { } } // Simplified logic to check for a color-only Badge (no icon, no text) - const hasColorProp = hasProp(openingElement.attributes, "color"); - const hasRole = getPropValue(getProp(openingElement.attributes, "role")) === "img"; - const hasAriaLabel = hasProp(openingElement.attributes, "aria-label"); + const roleProp = (0, jsx_ast_utils_2.getProp)(openingElement.attributes, "role"); + const hasColorProp = (0, jsx_ast_utils_1.hasProp)(openingElement.attributes, "color"); + const hasRole = !!roleProp && (0, jsx_ast_utils_2.getPropValue)(roleProp) === "img"; + const hasAriaLabel = (0, jsx_ast_utils_1.hasProp)(openingElement.attributes, "aria-label"); // If it's color-only, ensure it has role="img" and aria-label if (!hasIconProp && !(hasRole && hasAriaLabel)) { if (hasColorProp) { @@ -95,4 +97,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/breadcrumb-needs-labelling.d.ts b/dist/lib/rules/breadcrumb-needs-labelling.d.ts index de4c0ec..9376036 100644 --- a/dist/lib/rules/breadcrumb-needs-labelling.d.ts +++ b/dist/lib/rules/breadcrumb-needs-labelling.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noUnlabelledBreadcrumb", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/breadcrumb-needs-labelling.js b/dist/lib/rules/breadcrumb-needs-labelling.js index d3b50aa..ae5333d 100644 --- a/dist/lib/rules/breadcrumb-needs-labelling.js +++ b/dist/lib/rules/breadcrumb-needs-labelling.js @@ -1,14 +1,16 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const labelUtils_1 = require("../util/labelUtils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -21,7 +23,6 @@ module.exports = { recommended: false, url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, create(context) { @@ -29,12 +30,12 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a Breadcrumb, return - if (elementType(node) !== "Breadcrumb") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "Breadcrumb") { return; } // if the Breadcrumb has a label, if the Breadcrumb has an associated label, return - if (hasNonEmptyProp(node.attributes, "aria-label") || //aria-label - hasAssociatedLabelViaAriaLabelledBy(node, context) // aria-labelledby + if ((0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-label") || //aria-label + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(node, context) // aria-labelledby ) { return; } @@ -46,4 +47,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/buttons/compound-button-needs-labelling.d.ts b/dist/lib/rules/buttons/compound-button-needs-labelling.d.ts index 3f05421..f2a0058 100644 --- a/dist/lib/rules/buttons/compound-button-needs-labelling.d.ts +++ b/dist/lib/rules/buttons/compound-button-needs-labelling.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let missingAriaLabel: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingAriaLabel", [], { + JSXElement(node: TSESTree.JSXElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/buttons/compound-button-needs-labelling.js b/dist/lib/rules/buttons/compound-button-needs-labelling.js index 1706449..7d83385 100644 --- a/dist/lib/rules/buttons/compound-button-needs-labelling.js +++ b/dist/lib/rules/buttons/compound-button-needs-labelling.js @@ -1,15 +1,18 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../../util/hasNonEmptyProp"); -const { hasToolTipParent } = require("../../util/hasTooltipParent"); -const { hasTextContentChild } = require("../../util/hasTextContentChild"); -const { hasAssociatedLabelViaAriaLabelledBy } = require("../../util/labelUtils"); -var elementType = require("jsx-ast-utils").elementType; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../../util/hasNonEmptyProp"); +const hasTooltipParent_1 = require("../../util/hasTooltipParent"); +const hasTextContentChild_1 = require("../../util/hasTextContentChild"); +const labelUtils_1 = require("../../util/labelUtils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -20,7 +23,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Compound buttons must have accessible labelling: title, aria-label, aria-labelledby, aria-describedby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -32,17 +35,17 @@ module.exports = { JSXElement(node) { const openingElement = node.openingElement; // if it is not a Compound button, return - if (elementType(openingElement) !== "CompoundButton") { + if ((0, jsx_ast_utils_1.elementType)(openingElement) !== "CompoundButton") { return; } // if it has a tooltip parent Or has text content Or has an associated label or has secondaryContent, return - if (hasToolTipParent(context) || - hasTextContentChild(node) || - hasAssociatedLabelViaAriaLabelledBy(openingElement, context) || - hasNonEmptyProp(openingElement.attributes, "secondaryContent")) { + if ((0, hasTooltipParent_1.hasToolTipParent)(context) || + (0, hasTextContentChild_1.hasTextContentChild)(node) || + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(openingElement, context) || + (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "secondaryContent")) { return; } - const hasAccessibleLabelling = hasNonEmptyProp(openingElement.attributes, "title") || hasNonEmptyProp(openingElement.attributes, "aria-label"); + const hasAccessibleLabelling = (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "title") || (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "aria-label"); // if it has no accessible name, report error if (!hasAccessibleLabelling) { context.report({ @@ -53,4 +56,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/buttons/image-button-missing-aria.d.ts b/dist/lib/rules/buttons/image-button-missing-aria.d.ts index 3f05421..f2a0058 100644 --- a/dist/lib/rules/buttons/image-button-missing-aria.d.ts +++ b/dist/lib/rules/buttons/image-button-missing-aria.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let missingAriaLabel: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingAriaLabel", [], { + JSXElement(node: TSESTree.JSXElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/buttons/image-button-missing-aria.js b/dist/lib/rules/buttons/image-button-missing-aria.js index 4cfac1a..aa8ac6f 100644 --- a/dist/lib/rules/buttons/image-button-missing-aria.js +++ b/dist/lib/rules/buttons/image-button-missing-aria.js @@ -1,17 +1,19 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../../util/hasNonEmptyProp"); -const { hasToolTipParent } = require("../../util/hasTooltipParent"); -const { hasTextContentChild } = require("../../util/hasTextContentChild"); -const { hasAssociatedLabelViaAriaLabelledBy } = require("../../util/labelUtils"); -const { applicableComponents } = require("../../applicableComponents/buttonBasedComponents"); -var hasProp = require("jsx-ast-utils").hasProp; -var elementType = require("jsx-ast-utils").elementType; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../../util/hasNonEmptyProp"); +const hasTooltipParent_1 = require("../../util/hasTooltipParent"); +const hasTextContentChild_1 = require("../../util/hasTextContentChild"); +const labelUtils_1 = require("../../util/labelUtils"); +const buttonBasedComponents_1 = require("../../applicableComponents/buttonBasedComponents"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -22,7 +24,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Image buttons must have accessible labelling: title, aria-label, aria-labelledby, aria-describedby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -34,26 +36,26 @@ module.exports = { JSXElement(node) { const openingElement = node.openingElement; // if it is not a button, return - if (!applicableComponents.includes(elementType(openingElement))) { + if (!buttonBasedComponents_1.applicableComponents.includes((0, jsx_ast_utils_1.elementType)(openingElement))) { return; } // if it is not an icon button, return - if (!hasProp(openingElement.attributes, "icon")) { + if (!(0, jsx_ast_utils_1.hasProp)(openingElement.attributes, "icon")) { return; } // if it has a tooltip parent, return - if (hasToolTipParent(context)) { + if ((0, hasTooltipParent_1.hasToolTipParent)(context)) { return; } // if it has text content, return - if (hasTextContentChild(node)) { + if ((0, hasTextContentChild_1.hasTextContentChild)(node)) { return; } // the button has an associated label - if (hasAssociatedLabelViaAriaLabelledBy(openingElement, context)) { + if ((0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(openingElement, context)) { return; } - const hasAccessibleLabelling = hasNonEmptyProp(openingElement.attributes, "title") || hasNonEmptyProp(openingElement.attributes, "aria-label"); + const hasAccessibleLabelling = (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "title") || (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "aria-label"); // if it has no accessible name, report error if (!hasAccessibleLabelling) { context.report({ @@ -64,4 +66,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/buttons/no-empty-buttons.d.ts b/dist/lib/rules/buttons/no-empty-buttons.d.ts index da25e0f..4765267 100644 --- a/dist/lib/rules/buttons/no-empty-buttons.d.ts +++ b/dist/lib/rules/buttons/no-empty-buttons.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let noEmptyButtons: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXElement(node: any): any; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noEmptyButtons", [], { + JSXElement(node: TSESTree.JSXElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/buttons/no-empty-buttons.js b/dist/lib/rules/buttons/no-empty-buttons.js index 78b0856..265fd97 100644 --- a/dist/lib/rules/buttons/no-empty-buttons.js +++ b/dist/lib/rules/buttons/no-empty-buttons.js @@ -1,15 +1,17 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasTextContentChild } = require("../../util/hasTextContentChild"); -const { hasNonEmptyProp } = require("../../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -var hasProp = require("jsx-ast-utils").hasProp; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasTextContentChild_1 = require("../../util/hasTextContentChild"); +const hasNonEmptyProp_1 = require("../../util/hasNonEmptyProp"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ const allowedComponents = ["Button", "ToggleButton", "SplitButton", "MenuButton", "CompoundButton"]; -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the lint rule messages: { @@ -20,7 +22,7 @@ module.exports = { // docs for the rule docs: { description: `Accessibility: ${allowedComponents.join(", ")} must either text content or icon or child component`, - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] // no options @@ -32,18 +34,19 @@ module.exports = { JSXElement(node) { const openingElement = node.openingElement; // if it is not a button, return - if (!allowedComponents.includes(elementType(openingElement))) { + if (!allowedComponents.includes((0, jsx_ast_utils_1.elementType)(openingElement))) { return; } // if it has text content, return - if (hasTextContentChild(node)) + if ((0, hasTextContentChild_1.hasTextContentChild)(node)) return; // if there is icon prop, return - if (hasProp(openingElement.attributes, "icon")) { + if ((0, jsx_ast_utils_1.hasProp)(openingElement.attributes, "icon")) { return; } // if split button has secondary content, return - if (elementType(openingElement) === "CompoundButton" && hasNonEmptyProp(openingElement.attribute, "secondaryContent")) { + if ((0, jsx_ast_utils_1.elementType)(openingElement) === "CompoundButton" && + (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "secondaryContent")) { return; } const hasChildren = node.children.length > 0; @@ -57,4 +60,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/checkbox-needs-labelling.d.ts b/dist/lib/rules/checkbox-needs-labelling.d.ts index 72b437b..55b9e4a 100644 --- a/dist/lib/rules/checkbox-needs-labelling.d.ts +++ b/dist/lib/rules/checkbox-needs-labelling.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let noUnlabelledCheckbox: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXOpeningElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noUnlabelledCheckbox", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/checkbox-needs-labelling.js b/dist/lib/rules/checkbox-needs-labelling.js index 24e84d4..11344b2 100644 --- a/dist/lib/rules/checkbox-needs-labelling.js +++ b/dist/lib/rules/checkbox-needs-labelling.js @@ -1,14 +1,17 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const labelUtils_1 = require("../util/labelUtils"); +const hasFieldParent_1 = require("../util/hasFieldParent"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -20,7 +23,7 @@ module.exports = { docs: { // DONE description: "Accessibility: Checkbox without label must have an accessible and visual label: aria-labelledby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -31,15 +34,15 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a Checkbox, return - if (elementType(node) !== "Checkbox") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "Checkbox") { return; } // if the Checkbox has a label, if the Switch has an associated label, return - if (hasNonEmptyProp(node.attributes, "label") || - hasFieldParent(context) || - isInsideLabelTag(context) || - hasAssociatedLabelViaHtmlFor(node, context) || - hasAssociatedLabelViaAriaLabelledBy(node, context)) { + if ((0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "label") || + (0, hasFieldParent_1.hasFieldParent)(context) || + (0, labelUtils_1.isInsideLabelTag)(context) || + (0, labelUtils_1.hasAssociatedLabelViaHtmlFor)(node, context) || + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(node, context)) { return; } // if it has no visual labelling, report error @@ -50,4 +53,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/combobox-needs-labelling.d.ts b/dist/lib/rules/combobox-needs-labelling.d.ts index de4c0ec..d855084 100644 --- a/dist/lib/rules/combobox-needs-labelling.d.ts +++ b/dist/lib/rules/combobox-needs-labelling.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noUnlabelledCombobox", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/combobox-needs-labelling.js b/dist/lib/rules/combobox-needs-labelling.js index ebd4427..1124820 100644 --- a/dist/lib/rules/combobox-needs-labelling.js +++ b/dist/lib/rules/combobox-needs-labelling.js @@ -1,15 +1,17 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const labelUtils_1 = require("../util/labelUtils"); +const hasFieldParent_1 = require("../util/hasFieldParent"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -22,7 +24,6 @@ module.exports = { recommended: false, url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, create(context) { @@ -30,15 +31,15 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a Combobox, return - if (elementType(node) !== "Combobox") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "Combobox") { return; } // if the Combobox has a label, if the Combobox has an associated label, return - if (hasFieldParent(context) || - hasNonEmptyProp(node.attributes, "aria-label") || //aria-label, not recommended but will work for screen reader users - isInsideLabelTag(context) || // wrapped in label - hasAssociatedLabelViaHtmlFor(node, context) || // label with htmlFor - hasAssociatedLabelViaAriaLabelledBy(node, context) // aria-labelledby + if ((0, hasFieldParent_1.hasFieldParent)(context) || + (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-label") || //aria-label, not recommended but will work for screen reader users + (0, labelUtils_1.isInsideLabelTag)(context) || // wrapped in label + (0, labelUtils_1.hasAssociatedLabelViaHtmlFor)(node, context) || // label with htmlFor + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(node, context) // aria-labelledby ) { return; } @@ -50,4 +51,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/dialogbody-needs-title-content-and-actions.d.ts b/dist/lib/rules/dialogbody-needs-title-content-and-actions.d.ts index de4c0ec..717e62d 100644 --- a/dist/lib/rules/dialogbody-needs-title-content-and-actions.d.ts +++ b/dist/lib/rules/dialogbody-needs-title-content-and-actions.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"dialogBodyOneTitleOneContentOneFooter", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/dialogbody-needs-title-content-and-actions.js b/dist/lib/rules/dialogbody-needs-title-content-and-actions.js index ef3deb6..003bf2c 100644 --- a/dist/lib/rules/dialogbody-needs-title-content-and-actions.js +++ b/dist/lib/rules/dialogbody-needs-title-content-and-actions.js @@ -1,11 +1,13 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { messages: { dialogBodyOneTitleOneContentOneFooter: "ensure DialogBody has exactly one header,one content and one footer" @@ -13,29 +15,36 @@ module.exports = { type: "problem", // `problem`, `suggestion`, or `layout` docs: { description: "A DialogBody should have a header(DialogTitle), content(DialogContent), and footer(DialogActions)", - recommended: true, + recommended: "strict", url: "https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/" // URL to the documentation page for this rule }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, create(context) { return { JSXOpeningElement(node) { - if (node.name.name !== "DialogBody") { + if (node.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier && node.name.name !== "DialogBody") { return; } - const children = node.parent.children.filter(child => child.type === "JSXElement"); - const hasOneTitle = children.filter(child => child.openingElement.name.name === "DialogTitle").length === 1; - const hasOneContnet = children.filter(child => child.openingElement.name.name === "DialogContent").length === 1; - const hasOneAction = children.filter(child => child.openingElement.name.name === "DialogActions").length === 1; - if (!hasOneTitle || !hasOneContnet || !hasOneAction || children.length !== 3) { - context.report({ - node, - messageId: "dialogBodyOneTitleOneContentOneFooter" - }); + const children = node.parent && + node.parent.type === utils_1.AST_NODE_TYPES.JSXElement && + node.parent.children.filter(child => child.type === "JSXElement"); + if (children) { + const hasOneTitle = children.filter(child => child.openingElement.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "DialogTitle").length === 1; + const hasOneContnet = children.filter(child => child.openingElement.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "DialogContent").length === 1; + const hasOneAction = children.filter(child => child.openingElement.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "DialogActions").length === 1; + if (!hasOneTitle || !hasOneContnet || !hasOneAction || children.length !== 3) { + context.report({ + node, + messageId: "dialogBodyOneTitleOneContentOneFooter" + }); + } } } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/dialogsurface-needs-aria.d.ts b/dist/lib/rules/dialogsurface-needs-aria.d.ts index de4c0ec..651b4c5 100644 --- a/dist/lib/rules/dialogsurface-needs-aria.d.ts +++ b/dist/lib/rules/dialogsurface-needs-aria.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingAriaOnDialogSurface", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/dialogsurface-needs-aria.js b/dist/lib/rules/dialogsurface-needs-aria.js index 3889df6..156b980 100644 --- a/dist/lib/rules/dialogsurface-needs-aria.js +++ b/dist/lib/rules/dialogsurface-needs-aria.js @@ -1,15 +1,17 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasAssociatedAriaText } = require("../util/labelUtils"); -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const { hasTextContentChild } = require("../util/hasTextContentChild"); -var elementType = require("jsx-ast-utils").elementType; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const labelUtils_1 = require("../util/labelUtils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const hasTextContentChild_1 = require("../util/hasTextContentChild"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -20,7 +22,7 @@ module.exports = { // docs for the rule docs: { description: "DialogueSurface need accessible labelling: aria-describedby on DialogueSurface and aria-label or aria-labelledby(if DialogueTitle is missing)", - recommended: true, + recommended: "strict", url: "https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/" // URL to the documentation page for this rule }, schema: [] @@ -30,30 +32,40 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a DialogSurface, return - if (elementType(node) !== "DialogSurface") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "DialogSurface") { return; } // determine if DialogSurface as aria-describedby - const hasAriaDescribedBy = hasAssociatedAriaText(node, context, "aria-describedby"); + const hasAriaDescribedBy = (0, labelUtils_1.hasAssociatedAriaText)(node, context, "aria-describedby"); // find DialogBody Component - const dialogueSurfaceChildren = node.parent.children.filter(child => child.type === "JSXElement"); - const DialogBodyNode = dialogueSurfaceChildren.find(child => child.openingElement.name.name === "DialogBody"); - // find DialogTitle inside DialogBody Component - const dialogueBodyChildren = DialogBodyNode && DialogBodyNode.children.filter(child => child.type === "JSXElement"); - const DialogTitleNode = dialogueBodyChildren && dialogueBodyChildren.find(child => child.openingElement.name.name === "DialogTitle"); - // determine if DialogueText has any text content - const hasDialogTitleText = DialogTitleNode && hasTextContentChild(DialogTitleNode); - // determine if DialogueText or aria-label is present - const hasTitleOrAriaLabelledBy = hasDialogTitleText || hasNonEmptyProp(node.attributes, "aria-label") || hasAssociatedAriaText(node, context, "aria-labelledby"); - // if the DialogSurface has aria labelling and description, return - if (hasAriaDescribedBy && hasTitleOrAriaLabelledBy) { - return; + const dialogueSurfaceChildren = node.parent && + node.parent.type === utils_1.AST_NODE_TYPES.JSXElement && + node.parent.children.filter(child => child.type === "JSXElement"); + if (dialogueSurfaceChildren) { + const DialogBodyNode = dialogueSurfaceChildren.find(child => child.openingElement.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "DialogBody"); + // find DialogTitle inside DialogBody Component + const dialogueBodyChildren = DialogBodyNode && DialogBodyNode.children.filter(child => child.type === "JSXElement"); + const DialogTitleNode = dialogueBodyChildren && + dialogueBodyChildren.find(child => child.openingElement.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "DialogTitle"); + // determine if DialogueText has any text content + const hasDialogTitleText = DialogTitleNode && (0, hasTextContentChild_1.hasTextContentChild)(DialogTitleNode); + // determine if DialogueText or aria-label is present + const hasTitleOrAriaLabelledBy = hasDialogTitleText || + (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-label") || + (0, labelUtils_1.hasAssociatedAriaText)(node, context, "aria-labelledby"); + // if the DialogSurface has aria labelling and description, return + if (hasAriaDescribedBy && hasTitleOrAriaLabelledBy) { + return; + } + context.report({ + node, + messageId: `missingAriaOnDialogSurface` + }); } - context.report({ - node, - messageId: `missingAriaOnDialogSurface` - }); } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/dropdown-needs-labelling.d.ts b/dist/lib/rules/dropdown-needs-labelling.d.ts index e1e9aaf..dbdb20e 100644 --- a/dist/lib/rules/dropdown-needs-labelling.d.ts +++ b/dist/lib/rules/dropdown-needs-labelling.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let missingLabelOrAriaLabeledByInDropdown: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: null; - } - let schema: never[]; -} -export function create(context: any): { - JSXOpeningElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingLabelOrAriaLabeledByInDropdown", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/dropdown-needs-labelling.js b/dist/lib/rules/dropdown-needs-labelling.js index d4b19f8..ccdf2e6 100644 --- a/dist/lib/rules/dropdown-needs-labelling.js +++ b/dist/lib/rules/dropdown-needs-labelling.js @@ -1,13 +1,16 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, hasAssociatedLabelViaHtmlFor, isInsideLabelTag } = require("../util/labelUtils"); -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const labelUtils_1 = require("../util/labelUtils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -18,8 +21,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Dropdown menu must have an id and it needs to be linked via htmlFor of a Label", - recommended: true, - url: null + recommended: "strict" }, schema: [] }, @@ -29,17 +31,17 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a Dropdown, return - if (elementType(node) !== "Dropdown") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "Dropdown") { return; } // if the dropdown has a aria-LabeledBy with same value present in id of Label, return (Most recommended) // if the dropdown has an id and a label with htmlFor with sanme value as id, return // if the dropdown has an associated label, return // if the dropdown is inside Label tag, return - if (hasAssociatedLabelViaHtmlFor(node, context) || - hasAssociatedLabelViaAriaLabelledBy(node, context) || - hasNonEmptyProp(node.attributes, "aria-label") || - isInsideLabelTag(context)) { + if ((0, labelUtils_1.hasAssociatedLabelViaHtmlFor)(node, context) || + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(node, context) || + (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-label") || + (0, labelUtils_1.isInsideLabelTag)(context)) { return; } // if it has no visual labelling, report error @@ -50,4 +52,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/input-components-require-accessible-name.d.ts b/dist/lib/rules/input-components-require-accessible-name.d.ts index 27bb3d1..00b3681 100644 --- a/dist/lib/rules/input-components-require-accessible-name.d.ts +++ b/dist/lib/rules/input-components-require-accessible-name.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let missingLabelOnInput: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXOpeningElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingLabelOnInput", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/input-components-require-accessible-name.js b/dist/lib/rules/input-components-require-accessible-name.js index a63ee2f..6aa199b 100644 --- a/dist/lib/rules/input-components-require-accessible-name.js +++ b/dist/lib/rules/input-components-require-accessible-name.js @@ -1,25 +1,28 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { elementType } = require("jsx-ast-utils"); -const { isInsideLabelTag, hasAssociatedLabelViaHtmlFor, hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); -const { applicableComponents } = require("../applicableComponents/inputBasedComponents"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const labelUtils_1 = require("../util/labelUtils"); +const hasFieldParent_1 = require("../util/hasFieldParent"); +const inputBasedComponents_1 = require("../applicableComponents/inputBasedComponents"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { - missingLabelOnInput: `Accessibility - input fields must have a aria label associated with it: ${applicableComponents.join(", ")}` + missingLabelOnInput: `Accessibility - input fields must have a aria label associated with it: ${inputBasedComponents_1.applicableComponents.join(", ")}` }, // "problem" means the rule is identifying code that either will cause an error or may cause a confusing behavior: https://eslint.org/docs/latest/developer-guide/working-with-rules type: "problem", // docs for the rule docs: { description: "Accessibility: Input fields must have accessible labelling: aria-label, aria-labelledby or an associated label", - recommended: true, + recommended: "strict", url: "https://www.w3.org/WAI/tutorials/forms/labels/" // URL to the documentation page for this rule }, schema: [] @@ -29,14 +32,14 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a listed component, return - if (!applicableComponents.includes(elementType(node))) { + if (!inputBasedComponents_1.applicableComponents.includes((0, jsx_ast_utils_1.elementType)(node))) { return; } // wrapped in Label tag, labelled with htmlFor, labelled with aria-labelledby - if (hasFieldParent(context) || - isInsideLabelTag(context) || - hasAssociatedLabelViaHtmlFor(node, context) || - hasAssociatedLabelViaAriaLabelledBy(node, context)) { + if ((0, hasFieldParent_1.hasFieldParent)(context) || + (0, labelUtils_1.isInsideLabelTag)(context) || + (0, labelUtils_1.hasAssociatedLabelViaHtmlFor)(node, context) || + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(node, context)) { return; } context.report({ @@ -46,4 +49,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/link-missing-labelling.d.ts b/dist/lib/rules/link-missing-labelling.d.ts index de4c0ec..8c36a14 100644 --- a/dist/lib/rules/link-missing-labelling.d.ts +++ b/dist/lib/rules/link-missing-labelling.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingAriaLabel" | "missingHref", [], { + JSXElement(node: TSESTree.JSXElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/link-missing-labelling.js b/dist/lib/rules/link-missing-labelling.js index 5268a79..e4ebc47 100644 --- a/dist/lib/rules/link-missing-labelling.js +++ b/dist/lib/rules/link-missing-labelling.js @@ -1,22 +1,24 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { elementType } = require("jsx-ast-utils"); -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const { hasTextContentChild } = require("../util/hasTextContentChild"); -const { hasLabelledChildImage } = require("../util/hasLabelledChildImage"); -const { linkBasedComponents } = require("../applicableComponents/linkBasedComponents"); -const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const hasTextContentChild_1 = require("../util/hasTextContentChild"); +const hasLabelledChildImage_1 = require("../util/hasLabelledChildImage"); +const linkBasedComponents_1 = require("../applicableComponents/linkBasedComponents"); +const labelUtils_1 = require("../util/labelUtils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { type: "problem", docs: { description: "Accessibility: Image links must have an accessible name. Add either text content, labelling to the image or labelling to the link itself.", - recommended: true, + recommended: "strict", url: "https://www.w3.org/WAI/standards-guidelines/act/rules/c487ae/" // URL to the documentation page for this rule }, messages: { @@ -36,10 +38,10 @@ module.exports = { JSXElement(node) { const openingElement = node.openingElement; // if it's not a link based component, return - if (!linkBasedComponents.includes(elementType(openingElement))) { + if (!linkBasedComponents_1.linkBasedComponents.includes((0, jsx_ast_utils_1.elementType)(openingElement))) { return; } - const hasHref = hasNonEmptyProp(openingElement.attributes, "href"); + const hasHref = (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "href"); // check if the link has an href if (!hasHref) { context.report({ @@ -48,18 +50,18 @@ module.exports = { }); } // if it has text content, return - if (hasTextContentChild(node)) { + if ((0, hasTextContentChild_1.hasTextContentChild)(node)) { return; } // if there is a containing image and it is labelled correctly, return - const hasAccessibleImage = hasLabelledChildImage(node); + const hasAccessibleImage = (0, hasLabelledChildImage_1.hasLabelledChildImage)(node); if (hasAccessibleImage) { return; } // Check if there is an accessible link - const linkHasAccessibleLabel = hasNonEmptyProp(openingElement.attributes, "title") || - hasNonEmptyProp(openingElement.attributes, "aria-label") || - hasAssociatedLabelViaAriaLabelledBy(openingElement, context); + const linkHasAccessibleLabel = (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "title") || + (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "aria-label") || + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(openingElement, context); if (linkHasAccessibleLabel) { return; } @@ -73,4 +75,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/menu-item-needs-labelling.d.ts b/dist/lib/rules/menu-item-needs-labelling.d.ts index de4c0ec..b830d80 100644 --- a/dist/lib/rules/menu-item-needs-labelling.d.ts +++ b/dist/lib/rules/menu-item-needs-labelling.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noUnlabelledMenuItem", [], { + JSXElement(node: TSESTree.JSXElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/menu-item-needs-labelling.js b/dist/lib/rules/menu-item-needs-labelling.js index 3e2e296..6b19020 100644 --- a/dist/lib/rules/menu-item-needs-labelling.js +++ b/dist/lib/rules/menu-item-needs-labelling.js @@ -1,16 +1,18 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); -const { hasTextContentChild } = require("../util/hasTextContentChild"); -const { hasToolTipParent } = require("../util/hasTooltipParent"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const labelUtils_1 = require("../util/labelUtils"); +const hasTextContentChild_1 = require("../util/hasTextContentChild"); +const hasTooltipParent_1 = require("../util/hasTooltipParent"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -20,10 +22,9 @@ module.exports = { type: "problem", docs: { description: "Accessibility: MenuItem without label must have an accessible and visual label: aria-labelledby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, create(context) { @@ -32,14 +33,14 @@ module.exports = { JSXElement(node) { const openingElement = node.openingElement; // if it is not a MenuItem, return - if (elementType(openingElement) !== "MenuItem") { + if ((0, jsx_ast_utils_1.elementType)(openingElement) !== "MenuItem") { return; } // if the MenuItem has a text, label or an associated label, return - if (hasNonEmptyProp(openingElement.attributes, "aria-label") || //aria-label, not recommended but will work for screen reader users - hasAssociatedLabelViaAriaLabelledBy(openingElement, context) || // aria-labelledby - hasTextContentChild(node) || // has text content - hasToolTipParent(context) // has tooltip parent, not recommended but will work for screen reader users + if ((0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "aria-label") || //aria-label, not recommended but will work for screen reader users + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(openingElement, context) || // aria-labelledby + (0, hasTextContentChild_1.hasTextContentChild)(node) || // has text content + (0, hasTooltipParent_1.hasToolTipParent)(context) // has tooltip parent, not recommended but will work for screen reader users ) { return; } @@ -51,4 +52,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/no-empty-components.d.ts b/dist/lib/rules/no-empty-components.d.ts index de4c0ec..5ebe065 100644 --- a/dist/lib/rules/no-empty-components.d.ts +++ b/dist/lib/rules/no-empty-components.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noEmptyComponents", [], { + JSXElement(node: TSESTree.JSXElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/no-empty-components.js b/dist/lib/rules/no-empty-components.js index daae293..0528eaa 100644 --- a/dist/lib/rules/no-empty-components.js +++ b/dist/lib/rules/no-empty-components.js @@ -1,14 +1,16 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -var elementType = require("jsx-ast-utils").elementType; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ // Define an array of allowed component names const allowedComponents = ["Text", "Label", "Combobox", "Breadcrumb", "Dropdown", "Accordion", "AccordionItem", "AccordionPanel"]; -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the lint rule messages: { @@ -17,10 +19,8 @@ module.exports = { type: "problem", // `problem`, `suggestion`, or `layout` docs: { description: "FluentUI components should not be empty", - recommended: true, - url: null // URL to the documentation page for this rule + recommended: "strict" }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, // create (function) returns an object with methods that ESLint calls to “visit” nodes while traversing the abstract syntax tree @@ -30,7 +30,7 @@ module.exports = { JSXElement(node) { const openingElement = node.openingElement; // if it is not a listed component, return - if (!allowedComponents.includes(elementType(openingElement))) { + if (!allowedComponents.includes((0, jsx_ast_utils_1.elementType)(openingElement))) { return; } const hasChildren = node.children.length > 0; @@ -44,4 +44,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/progressbar-needs-labelling.d.ts b/dist/lib/rules/progressbar-needs-labelling.d.ts index 180690f..85b4d29 100644 --- a/dist/lib/rules/progressbar-needs-labelling.d.ts +++ b/dist/lib/rules/progressbar-needs-labelling.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let noUnlabelledProgressbar: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXOpeningElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noUnlabelledProgressbar", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/progressbar-needs-labelling.js b/dist/lib/rules/progressbar-needs-labelling.js index 33edfbf..1b79719 100644 --- a/dist/lib/rules/progressbar-needs-labelling.js +++ b/dist/lib/rules/progressbar-needs-labelling.js @@ -1,13 +1,16 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasFieldParent } = require("../util/hasFieldParent"); -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const elementType = require("jsx-ast-utils").elementType; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasFieldParent_1 = require("../util/hasFieldParent"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -18,7 +21,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Progressbar must have aria-valuemin, aria-valuemax, aria-valuenow, aria-describedby and either aria-label or aria-labelledby attributes", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -29,24 +32,24 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a ProgressBar, return - if (elementType(node) !== "ProgressBar") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "ProgressBar") { return; } // check if the ProgressBar has a Field parent - const hasFieldParentCheck = hasFieldParent(context); + const hasFieldParentCheck = (0, hasFieldParent_1.hasFieldParent)(context); // If no Field parent, ensure one of the aria-label or aria-labelledby is provided as well as aria-describedby - const hasLabelling = (hasNonEmptyProp(node.attributes, "aria-label") || hasNonEmptyProp(node.attributes, "aria-labelledby")) && - hasNonEmptyProp(node.attributes, "aria-describedby"); + const hasLabelling = ((0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-label") || (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-labelledby")) && + (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-describedby"); const mandatoryAttributes = []; // Check if max is provided, if not, require aria-valuemax - const hasMaxProp = hasNonEmptyProp(node.attributes, "max"); + const hasMaxProp = (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "max"); if (!hasMaxProp) { mandatoryAttributes.push("aria-valuemax"); mandatoryAttributes.push("aria-valuemin"); mandatoryAttributes.push("aria-valuenow"); } // If all mandatory attributes (including optional aria-valuemax) are present, return - if (mandatoryAttributes.every(attribute => hasNonEmptyProp(node.attributes, attribute)) && + if (mandatoryAttributes.every(attribute => (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, attribute)) && (hasFieldParentCheck || hasLabelling)) { return; } @@ -58,4 +61,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/radio-button-missing-label.d.ts b/dist/lib/rules/radio-button-missing-label.d.ts index 7465799..23ca7db 100644 --- a/dist/lib/rules/radio-button-missing-label.d.ts +++ b/dist/lib/rules/radio-button-missing-label.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let noUnlabeledRadioButton: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXOpeningElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noUnlabeledRadioButton", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/radio-button-missing-label.js b/dist/lib/rules/radio-button-missing-label.js index 0335354..e6812ac 100644 --- a/dist/lib/rules/radio-button-missing-label.js +++ b/dist/lib/rules/radio-button-missing-label.js @@ -1,14 +1,17 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const labelUtils_1 = require("../util/labelUtils"); +const hasFieldParent_1 = require("../util/hasFieldParent"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -20,7 +23,7 @@ module.exports = { docs: { // DONE description: "Accessibility: Radio button without label must have an accessible and visual label: aria-labelledby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -31,16 +34,16 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a Checkbox, return - if (elementType(node) !== "Radio") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "Radio") { return; } // if the Checkbox has a label, if the Switch has an associated label, return - if (hasFieldParent(context) || - hasNonEmptyProp(node.attributes, "label") || - hasNonEmptyProp(node.attributes, "aria-label") || - isInsideLabelTag(context) || - hasAssociatedLabelViaHtmlFor(node, context) || - hasAssociatedLabelViaAriaLabelledBy(node, context)) { + if ((0, hasFieldParent_1.hasFieldParent)(context) || + (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "label") || + (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-label") || + (0, labelUtils_1.isInsideLabelTag)(context) || + (0, labelUtils_1.hasAssociatedLabelViaHtmlFor)(node, context) || + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(node, context)) { return; } // if it has no visual labelling, report error @@ -51,4 +54,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/radiogroup-missing-label.d.ts b/dist/lib/rules/radiogroup-missing-label.d.ts index aab1b22..ba22572 100644 --- a/dist/lib/rules/radiogroup-missing-label.d.ts +++ b/dist/lib/rules/radiogroup-missing-label.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let noUnlabeledRadioGroup: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXOpeningElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noUnlabeledRadioGroup", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/radiogroup-missing-label.js b/dist/lib/rules/radiogroup-missing-label.js index 98b15b6..817099d 100644 --- a/dist/lib/rules/radiogroup-missing-label.js +++ b/dist/lib/rules/radiogroup-missing-label.js @@ -1,14 +1,17 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const labelUtils_1 = require("../util/labelUtils"); +const hasFieldParent_1 = require("../util/hasFieldParent"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -20,7 +23,7 @@ module.exports = { docs: { // DONE description: "Accessibility: RadioGroup without label must have an accessible and visual label: aria-labelledby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -31,16 +34,16 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a Checkbox, return - if (elementType(node) !== "RadioGroup") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "RadioGroup") { return; } // if the Checkbox has a label, if the Switch has an associated label, return - if (hasFieldParent(context) || - hasNonEmptyProp(node.attributes, "label") || - hasNonEmptyProp(node.attributes, "aria-label") || - isInsideLabelTag(context) || - hasAssociatedLabelViaHtmlFor(node, context) || - hasAssociatedLabelViaAriaLabelledBy(node, context)) { + if ((0, hasFieldParent_1.hasFieldParent)(context) || + (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "label") || + (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-label") || + (0, labelUtils_1.isInsideLabelTag)(context) || + (0, labelUtils_1.hasAssociatedLabelViaHtmlFor)(node, context) || + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(node, context)) { return; } // if it has no visual labelling, report error @@ -51,4 +54,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/spin-button-needs-labelling.d.ts b/dist/lib/rules/spin-button-needs-labelling.d.ts index c49d72a..df462b9 100644 --- a/dist/lib/rules/spin-button-needs-labelling.d.ts +++ b/dist/lib/rules/spin-button-needs-labelling.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let noUnlabelledSpinButton: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXOpeningElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noUnlabelledSpinButton", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/spin-button-needs-labelling.js b/dist/lib/rules/spin-button-needs-labelling.js index 27ccbbe..eec2150 100644 --- a/dist/lib/rules/spin-button-needs-labelling.js +++ b/dist/lib/rules/spin-button-needs-labelling.js @@ -1,13 +1,16 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const labelUtils_1 = require("../util/labelUtils"); +const hasFieldParent_1 = require("../util/hasFieldParent"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -18,7 +21,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: SpinButtons must have an accessible label", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -29,14 +32,14 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a SpinButton, return - if (elementType(node) !== "SpinButton") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "SpinButton") { return; } // if the SpinButton has an associated label, return - if (hasFieldParent(context) || - isInsideLabelTag(context) || - hasAssociatedLabelViaHtmlFor(node, context) || - hasAssociatedLabelViaAriaLabelledBy(node, context)) { + if ((0, hasFieldParent_1.hasFieldParent)(context) || + (0, labelUtils_1.isInsideLabelTag)(context) || + (0, labelUtils_1.hasAssociatedLabelViaHtmlFor)(node, context) || + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(node, context)) { return; } // if it has no visual labelling, report error @@ -47,4 +50,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/spin-button-unrecommended-labelling.d.ts b/dist/lib/rules/spin-button-unrecommended-labelling.d.ts index 7fcb4f0..5de3d41 100644 --- a/dist/lib/rules/spin-button-unrecommended-labelling.d.ts +++ b/dist/lib/rules/spin-button-unrecommended-labelling.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let unRecommendedlabellingSpinButton: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXOpeningElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"unRecommendedlabellingSpinButton", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/spin-button-unrecommended-labelling.js b/dist/lib/rules/spin-button-unrecommended-labelling.js index 9dae79e..01cd595 100644 --- a/dist/lib/rules/spin-button-unrecommended-labelling.js +++ b/dist/lib/rules/spin-button-unrecommended-labelling.js @@ -1,13 +1,16 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const { hasToolTipParent } = require("../util/hasTooltipParent"); -var elementType = require("jsx-ast-utils").elementType; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const hasTooltipParent_1 = require("../util/hasTooltipParent"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible suggestion messages for the rule messages: { @@ -18,7 +21,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Unrecommended accessibility labelling - SpinButton", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -29,11 +32,11 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a SpinButton, return - if (elementType(node) !== "SpinButton") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "SpinButton") { return; } // if the SpinButton has an aria-label or is wrapped in a Tooltip, show warning - if (hasNonEmptyProp(node.attributes, "aria-label") || hasToolTipParent(context)) { + if ((0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-label") || (0, hasTooltipParent_1.hasToolTipParent)(context)) { context.report({ node, messageId: `unRecommendedlabellingSpinButton` @@ -42,4 +45,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/spinner-needs-labelling.d.ts b/dist/lib/rules/spinner-needs-labelling.d.ts index 30b60ae..bc40b13 100644 --- a/dist/lib/rules/spinner-needs-labelling.d.ts +++ b/dist/lib/rules/spinner-needs-labelling.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let noUnlabelledSpinner: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXOpeningElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noUnlabelledSpinner", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/spinner-needs-labelling.js b/dist/lib/rules/spinner-needs-labelling.js index c4f8aa5..bc0b298 100644 --- a/dist/lib/rules/spinner-needs-labelling.js +++ b/dist/lib/rules/spinner-needs-labelling.js @@ -1,12 +1,15 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const elementType = require("jsx-ast-utils").elementType; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -17,7 +20,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Spinner must have either aria-label or label, aria-live and aria-busy attributes", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -28,12 +31,12 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a Spinner, return - if (elementType(node) !== "Spinner") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "Spinner") { return; } - if (hasNonEmptyProp(node.attributes, "aria-busy") - && hasNonEmptyProp(node.attributes, "aria-live") - && (hasNonEmptyProp(node.attributes, "label") || hasNonEmptyProp(node.attributes, "aria-label"))) { + if ((0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-busy") && + (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-live") && + ((0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "label") || (0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-label"))) { return; } // if it has no visual labelling, report error @@ -44,4 +47,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/switch-needs-labelling.d.ts b/dist/lib/rules/switch-needs-labelling.d.ts index 8e61b45..9a4895d 100644 --- a/dist/lib/rules/switch-needs-labelling.d.ts +++ b/dist/lib/rules/switch-needs-labelling.d.ts @@ -1,15 +1,5 @@ -export namespace meta { - namespace messages { - let noUnlabelledSwitch: string; - } - let type: string; - namespace docs { - let description: string; - let recommended: boolean; - let url: string; - } - let schema: never[]; -} -export function create(context: any): { - JSXOpeningElement(node: any): void; -}; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"noUnlabelledSwitch", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/switch-needs-labelling.js b/dist/lib/rules/switch-needs-labelling.js index 6013633..3f357b6 100644 --- a/dist/lib/rules/switch-needs-labelling.js +++ b/dist/lib/rules/switch-needs-labelling.js @@ -1,14 +1,17 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); +const labelUtils_1 = require("../util/labelUtils"); +const hasFieldParent_1 = require("../util/hasFieldParent"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -19,7 +22,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Switch must have an accessible label", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -30,15 +33,15 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a Switch, return - if (elementType(node) !== "Switch") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "Switch") { return; } // if the Switch has a label, if the Switch has an associated label, return - if (hasNonEmptyProp(node.attributes, "label") || - hasFieldParent(context) || - isInsideLabelTag(context) || - hasAssociatedLabelViaHtmlFor(node, context) || - hasAssociatedLabelViaAriaLabelledBy(node, context)) { + if ((0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "label") || + (0, hasFieldParent_1.hasFieldParent)(context) || + (0, labelUtils_1.isInsideLabelTag)(context) || + (0, labelUtils_1.hasAssociatedLabelViaHtmlFor)(node, context) || + (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(node, context)) { return; } // if it has no visual labelling, report error @@ -49,4 +52,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/toolbar-missing-aria.d.ts b/dist/lib/rules/toolbar-missing-aria.d.ts index de4c0ec..1af37a3 100644 --- a/dist/lib/rules/toolbar-missing-aria.d.ts +++ b/dist/lib/rules/toolbar-missing-aria.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from "@typescript-eslint/utils"; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingLabelOnToolbar", [], { + JSXOpeningElement(node: TSESTree.JSXOpeningElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/toolbar-missing-aria.js b/dist/lib/rules/toolbar-missing-aria.js index 926fb8f..239fffd 100644 --- a/dist/lib/rules/toolbar-missing-aria.js +++ b/dist/lib/rules/toolbar-missing-aria.js @@ -1,14 +1,16 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const labelUtils_1 = require("../util/labelUtils"); +const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -19,7 +21,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Toolbars need accessible labelling: aria-label or aria-labelledby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/WAI/tutorials/forms/labels/" // URL to the documentation page for this rule }, schema: [] @@ -29,11 +31,11 @@ module.exports = { // visitor functions for different types of nodes JSXOpeningElement(node) { // if it is not a Toolbar, return - if (elementType(node) !== "Toolbar") { + if ((0, jsx_ast_utils_1.elementType)(node) !== "Toolbar") { return; } // if the Toolbar has aria labelling, return - if (hasNonEmptyProp(node.attributes, "aria-label") || hasAssociatedLabelViaAriaLabelledBy(node, context)) { + if ((0, hasNonEmptyProp_1.hasNonEmptyProp)(node.attributes, "aria-label") || (0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(node, context)) { return; } context.report({ @@ -43,4 +45,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/rules/tooltip-not-recommended.d.ts b/dist/lib/rules/tooltip-not-recommended.d.ts index de4c0ec..c0f910b 100644 --- a/dist/lib/rules/tooltip-not-recommended.d.ts +++ b/dist/lib/rules/tooltip-not-recommended.d.ts @@ -1,2 +1,5 @@ -declare const _exports: import("eslint").Rule.RuleModule; -export = _exports; +import { TSESTree } from '@typescript-eslint/utils'; +declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"tooltipNotRecommended", [], { + JSXElement(node: TSESTree.JSXElement): void; +}>; +export default rule; diff --git a/dist/lib/rules/tooltip-not-recommended.js b/dist/lib/rules/tooltip-not-recommended.js index 55f893e..b8b545a 100644 --- a/dist/lib/rules/tooltip-not-recommended.js +++ b/dist/lib/rules/tooltip-not-recommended.js @@ -1,15 +1,17 @@ +"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; -var elementType = require("jsx-ast-utils").elementType; -const { hasToolTipParent } = require("../util/hasTooltipParent"); +Object.defineProperty(exports, "__esModule", { value: true }); +const utils_1 = require("@typescript-eslint/utils"); +const jsx_ast_utils_1 = require("jsx-ast-utils"); +const hasTooltipParent_1 = require("../util/hasTooltipParent"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ // Define an array of allowed component names const allowedComponents = ["MenuItem", "SpinButton"]; -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the lint rule messages: { @@ -18,10 +20,8 @@ module.exports = { type: "suggestion", // `problem`, `suggestion`, or `layout` docs: { description: `Accessibility: Prefer text content or aria over a tooltip for these components ${allowedComponents.join(", ")}`, - recommended: true, - url: null // URL to the documentation page for this rule + recommended: 'strict', }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, // create (function) returns an object with methods that ESLint calls to “visit” nodes while traversing the abstract syntax tree @@ -31,11 +31,11 @@ module.exports = { JSXElement(node) { const openingElement = node.openingElement; // if it is not a listed component, return - if (!allowedComponents.includes(elementType(openingElement))) { + if (!allowedComponents.includes((0, jsx_ast_utils_1.elementType)(openingElement))) { return; } // if there are is tooltip, report - if (hasToolTipParent(context)) { + if ((0, hasTooltipParent_1.hasToolTipParent)(context)) { context.report({ node, messageId: `tooltipNotRecommended` @@ -44,4 +44,5 @@ module.exports = { } }; } -}; +}); +exports.default = rule; diff --git a/dist/lib/util/hasLabelledChildImage.js b/dist/lib/util/hasLabelledChildImage.js index 3449825..2970c63 100644 --- a/dist/lib/util/hasLabelledChildImage.js +++ b/dist/lib/util/hasLabelledChildImage.js @@ -18,9 +18,7 @@ function hasLabelledChildImage(node) { } // Check if there is an accessible image const hasAccessibleImage = flattenChildren(node).some(child => { - console.log("mergedImageComponents.includes(child.openingElement.name.name)::: ", mergedImageComponents.includes(child.openingElement.name.name)); if (child.type === "JSXElement" && mergedImageComponents.includes(child.openingElement.name.name)) { - console.log("here 3"); return hasProp(child.openingElement.attributes, "aria-hidden") || getPropValue(child.openingElement.attributes, "alt") ? false : hasNonEmptyProp(child.openingElement.attributes, "title") || diff --git a/lib/index.ts b/lib/index.ts index 6266604..3fcff30 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -3,6 +3,32 @@ console.log("Loading my-eslint-plugin"); import preferAriaOverTitleAttribute from "./rules/prefer-aria-over-title-attribute"; +import checkboxNeedsLabelling from "./rules/checkbox-needs-labelling"; +import imageButtonMissingAria from "./rules/buttons/image-button-missing-aria"; +import linkMissingLabelling from "./rules/link-missing-labelling"; +import inputComponentsRequireAccessibleName from "./rules/input-components-require-accessible-name"; +import menuItemNeedsLabelling from "./rules/menu-item-needs-labelling"; +import switchNeedsLabelling from "./rules/switch-needs-labelling"; +import toolbarMissingAria from "./rules/toolbar-missing-aria"; +import comboboxNeedsLabelling from "./rules/combobox-needs-labelling"; +import noEmptyComponents from "./rules/no-empty-components"; +import accordionHeaderNeedsLabelling from "./rules/accordion-header-needs-labelling"; +import accordionItemNeedsHeaderAndPanel from "./rules/accordion-item-needs-header-and-panel"; +import compoundButtonNeedsLabelling from "./rules/buttons/compound-button-needs-labelling"; +import noEmptyButtons from "./rules/buttons/no-empty-buttons"; +import spinButtonNeedsLabelling from "./rules/spin-button-needs-labelling"; +import spinButtonUnrecommendedLabelling from "./rules/spin-button-unrecommended-labelling"; +import breadcrumbNeedsLabelling from "./rules/breadcrumb-needs-labelling"; +import dropwdonNeedsLabelling from "./rules/dropdown-needs-labelling"; +import tooltipNotRecommended from "./rules/tooltip-not-recommended"; +import avatarNeedsName from "./rules/avatar-needs-name"; +import radioButtonMissingLabel from "./rules/radio-button-missing-label"; +import radiogroupMissingLabel from "./rules/radiogroup-missing-label"; +import dialogbodyNeedsTitleContentAndActions from "./rules/dialogbody-needs-title-content-and-actions"; +import dialogsurfaceNeedsAria from "./rules/dialogsurface-needs-aria"; +import spinnerNeedsLabelling from "./rules/spinner-needs-labelling"; +import badgeNeedsAccessibleName from "./rules/badge-needs-accessible-name"; +import progressbarNeedsLabelling from "./rules/progressbar-needs-labelling"; import fieldNeedsLabelling from "./rules/field-needs-labelling"; //------------------------------------------------------------------------------ // Requirements @@ -15,33 +41,33 @@ import fieldNeedsLabelling from "./rules/field-needs-labelling"; // import all rules in lib/rules module.exports = { rules: { - "checkbox-needs-labelling": require("./rules/checkbox-needs-labelling"), - "image-button-missing-aria": require("./rules/buttons/image-button-missing-aria"), - "link-missing-labelling": require("./rules/link-missing-labelling"), - "input-components-require-accessible-name": require("./rules/input-components-require-accessible-name"), - "menu-item-needs-labelling": require("./rules/menu-item-needs-labelling"), - "switch-needs-labelling": require("./rules/switch-needs-labelling"), - "toolbar-missing-aria": require("./rules/toolbar-missing-aria"), - "combobox-needs-labelling": require("./rules/combobox-needs-labelling"), - "no-empty-components": require("./rules/no-empty-components"), - "accordion-header-needs-labelling": require("./rules/accordion-header-needs-labelling"), - "accordion-item-needs-header-and-panel": require("./rules/accordion-item-needs-header-and-panel"), - "compound-button-needs-labelling": require("./rules/buttons/compound-button-needs-labelling"), - "no-empty-buttons": require("./rules/buttons/no-empty-buttons"), - "spin-button-needs-labelling": require("./rules/spin-button-needs-labelling"), - "spin-button-unrecommended-labelling": require("./rules/spin-button-unrecommended-labelling"), - "breadcrumb-needs-labelling": require("./rules/breadcrumb-needs-labelling"), - "dropdown-needs-labelling": require("./rules/dropdown-needs-labelling"), - "tooltip-not-recommended": require("./rules/tooltip-not-recommended"), - "avatar-needs-name": require("./rules/avatar-needs-name"), - "radio-button-missing-label": require("./rules/radio-button-missing-label"), - "radiogroup-missing-label": require("./rules/radiogroup-missing-label"), + "checkbox-needs-labelling": checkboxNeedsLabelling, + "image-button-missing-aria": imageButtonMissingAria, + "link-missing-labelling": linkMissingLabelling, + "input-components-require-accessible-name": inputComponentsRequireAccessibleName, + "menu-item-needs-labelling": menuItemNeedsLabelling, + "switch-needs-labelling": switchNeedsLabelling, + "toolbar-missing-aria": toolbarMissingAria, + "combobox-needs-labelling": comboboxNeedsLabelling, + "no-empty-components": noEmptyComponents, + "accordion-header-needs-labelling": accordionHeaderNeedsLabelling, + "accordion-item-needs-header-and-panel": accordionItemNeedsHeaderAndPanel, + "compound-button-needs-labelling": compoundButtonNeedsLabelling, + "no-empty-buttons": noEmptyButtons, + "spin-button-needs-labelling": spinButtonNeedsLabelling, + "spin-button-unrecommended-labelling": spinButtonUnrecommendedLabelling, + "breadcrumb-needs-labelling": breadcrumbNeedsLabelling, + "dropdown-needs-labelling": dropwdonNeedsLabelling, + "tooltip-not-recommended": tooltipNotRecommended, + "avatar-needs-name": avatarNeedsName, + "radio-button-missing-label": radioButtonMissingLabel, + "radiogroup-missing-label": radiogroupMissingLabel, "prefer-aria-over-title-attribute": preferAriaOverTitleAttribute, - "dialogbody-needs-title-content-and-actions": require("./rules/dialogbody-needs-title-content-and-actions"), - "dialogsurface-needs-aria": require("./rules/dialogsurface-needs-aria"), - "spinner-needs-labelling": require("./rules/spinner-needs-labelling"), - "badge-needs-accessible-name": require("./rules/badge-needs-accessible-name"), - "progressbar-needs-labelling": require("./rules/progressbar-needs-labelling"), + "dialogbody-needs-title-content-and-actions": dialogbodyNeedsTitleContentAndActions, + "dialogsurface-needs-aria": dialogsurfaceNeedsAria, + "spinner-needs-labelling": spinnerNeedsLabelling, + "badge-needs-accessible-name": badgeNeedsAccessibleName, + "progressbar-needs-labelling": progressbarNeedsLabelling, "field-needs-labelling": fieldNeedsLabelling }, configs: { diff --git a/lib/rules/accordion-header-needs-labelling.js b/lib/rules/accordion-header-needs-labelling.ts similarity index 70% rename from lib/rules/accordion-header-needs-labelling.js rename to lib/rules/accordion-header-needs-labelling.ts index b5b4974..943308b 100644 --- a/lib/rules/accordion-header-needs-labelling.js +++ b/lib/rules/accordion-header-needs-labelling.ts @@ -1,21 +1,20 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const { hasToolTipParent } = require("../util/hasTooltipParent"); -const { hasTextContentChild } = require("../util/hasTextContentChild"); -const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); -var hasProp = require("jsx-ast-utils").hasProp; -var elementType = require("jsx-ast-utils").elementType; +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType, hasProp } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { hasToolTipParent } from "../util/hasTooltipParent"; +import { hasTextContentChild } from "../util/hasTextContentChild"; +import { hasAssociatedLabelViaAriaLabelledBy } from "../util/labelUtils"; +import { JSXAttribute, JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { messages: { missingAriaLabel: "Accessibility: the accordion header must have an accessible name" @@ -24,21 +23,19 @@ module.exports = { docs: { description: "The accordion header is a button and it needs an accessibile name e.g. text content, aria-label, aria-labelledby.", - recommended: false, - url: null // URL to the documentation page for this rule + recommended: false }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, // create (function) returns an object with methods that ESLint calls to “visit” nodes while traversing the abstract syntax tree create(context) { return { // visitor functions for different types of nodes - JSXElement(node) { + JSXElement(node: TSESTree.JSXElement) { const openingElement = node.openingElement; // if it is not a AccordionHeader, return - if (elementType(openingElement) !== "AccordionHeader") { + if (elementType(openingElement as JSXOpeningElement) !== "AccordionHeader") { return; } @@ -48,7 +45,10 @@ module.exports = { } // if it is not an icon button, return - if (!hasProp(openingElement.attributes, "icon") && !hasProp(openingElement.attributes, "expandIcon")) { + if ( + !hasProp(openingElement.attributes as JSXAttribute[], "icon") && + !hasProp(openingElement.attributes as JSXAttribute[], "expandIcon") + ) { return; } @@ -75,4 +75,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/accordion-item-needs-header-and-panel.js b/lib/rules/accordion-item-needs-header-and-panel.ts similarity index 51% rename from lib/rules/accordion-item-needs-header-and-panel.js rename to lib/rules/accordion-item-needs-header-and-panel.ts index b3e62c0..97611cf 100644 --- a/lib/rules/accordion-item-needs-header-and-panel.js +++ b/lib/rules/accordion-item-needs-header-and-panel.ts @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; +import { AST_NODE_TYPES, ESLintUtils, TSESTree } from "@typescript-eslint/utils"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { messages: { accordionItemOneHeaderOnePanel: "ensure AccordionItem has exactly one header and one panel" @@ -16,25 +16,38 @@ module.exports = { type: "problem", // `problem`, `suggestion`, or `layout` docs: { description: "An AccordionItem needs exactly one header and one panel", - recommended: true, + recommended: "strict", url: "https://www.w3.org/WAI/ARIA/apg/patterns/accordion/" // URL to the documentation page for this rule }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, create(context) { return { - JSXOpeningElement(node) { - if (node.name.name !== "AccordionItem") { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { + if (node.name.type === AST_NODE_TYPES.JSXIdentifier && node.name.name !== "AccordionItem") { + return; + } + + if (!(node.parent && node.parent.type === AST_NODE_TYPES.JSXElement)) { return; } const children = node.parent.children.filter(child => child.type === "JSXElement"); - const hasOneHeader = children.filter(child => child.openingElement.name.name === "AccordionHeader").length === 1; + const hasOneHeader = + children.filter( + child => + child.openingElement.name.type === AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "AccordionHeader" + ).length === 1; - const hasOnePanel = children.filter(child => child.openingElement.name.name === "AccordionPanel").length === 1; + const hasOnePanel = + children.filter( + child => + child.openingElement.name.type === AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "AccordionPanel" + ).length === 1; if (!hasOneHeader || !hasOnePanel || children.length !== 2) { context.report({ @@ -45,5 +58,6 @@ module.exports = { } }; } -}; +}); +export default rule; diff --git a/lib/rules/avatar-needs-name.js b/lib/rules/avatar-needs-name.ts similarity index 76% rename from lib/rules/avatar-needs-name.js rename to lib/rules/avatar-needs-name.ts index 4578b03..5db732e 100644 --- a/lib/rules/avatar-needs-name.js +++ b/lib/rules/avatar-needs-name.ts @@ -1,17 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { JSXOpeningElement } from "estree-jsx"; +import { elementType } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { hasAssociatedLabelViaAriaLabelledBy } from "../util/labelUtils"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -23,7 +24,7 @@ module.exports = { docs: { // DONE description: "Accessibility: Avatar must have an accessible labelling: name, aria-label, aria-labelledby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -32,9 +33,9 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not an Avatar, return - if (elementType(node) !== "Avatar") { + if (elementType(node as JSXOpeningElement) !== "Avatar") { return; } @@ -55,4 +56,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/avoid-using-aria-describedby-for-primary-labelling.js b/lib/rules/avoid-using-aria-describedby-for-primary-labelling.ts similarity index 73% rename from lib/rules/avoid-using-aria-describedby-for-primary-labelling.js rename to lib/rules/avoid-using-aria-describedby-for-primary-labelling.ts index 8878738..431e594 100644 --- a/lib/rules/avoid-using-aria-describedby-for-primary-labelling.js +++ b/lib/rules/avoid-using-aria-describedby-for-primary-labelling.ts @@ -1,29 +1,28 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { applicableComponents: inputComponents } = require("../applicableComponents/inputBasedComponents"); -const { applicableComponents: buttonComponents } = require("../applicableComponents/buttonBasedComponents"); -const { elementType } = require("jsx-ast-utils"); -const { +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { JSXOpeningElement } from "estree-jsx"; +import { elementType } from "jsx-ast-utils"; +import { applicableComponents as inputComponents } from "../applicableComponents/inputBasedComponents"; +import { applicableComponents as buttonComponents } from "../applicableComponents/buttonBasedComponents"; +import { isInsideLabelTag, hasAssociatedLabelViaHtmlFor, hasAssociatedLabelViaAriaLabelledBy, hasAssociatedLabelViaAriaDescribedby -} = require("../util/labelUtils"); - -const { hasFieldParent } = require("../util/hasFieldParent"); -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const { hasToolTipParent } = require("../util/hasTooltipParent"); -const { hasTextContentChild } = require("../util/hasTextContentChild"); +} from "../util/labelUtils"; +import { hasFieldParent } from "../util/hasFieldParent"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { hasToolTipParent } from "../util/hasTooltipParent"; +import { hasTextContentChild } from "../util/hasTextContentChild"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { messages: { noAriaDescribedbyAsLabel: "Accessibility: aria-describedby provides additional context and is not meant for primary labeling." @@ -31,20 +30,18 @@ module.exports = { type: "suggestion", // `problem`, `suggestion`, or `layout` docs: { description: "aria-describedby provides additional context and is not meant for primary labeling.", - recommended: true, - url: null // URL to the documentation page for this rule + recommended: "strict" }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, create(context) { return { - JSXElement(node) { + JSXElement(node: TSESTree.JSXElement) { const openingElement = node.openingElement; if ( - buttonComponents.includes(elementType(openingElement)) && // It's a button-based component + buttonComponents.includes(elementType(openingElement as JSXOpeningElement)) && // It's a button-based component !hasToolTipParent(context) && // It doesn't have a tooltip parent !hasTextContentChild(node) && // It doesn't have text content !hasNonEmptyProp(openingElement.attributes, "title") && // Doesn't have a title @@ -59,7 +56,7 @@ module.exports = { } if ( - inputComponents.includes(elementType(openingElement)) && // It's an input component + inputComponents.includes(elementType(openingElement as JSXOpeningElement)) && // It's an input component !hasFieldParent(context) && // It doesn't have a field parent !isInsideLabelTag(context) && // It's not inside a label tag !hasAssociatedLabelViaHtmlFor(openingElement, context) && // Doesn't have a label via htmlFor @@ -74,4 +71,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/badge-needs-accessible-name.js b/lib/rules/badge-needs-accessible-name.ts similarity index 76% rename from lib/rules/badge-needs-accessible-name.js rename to lib/rules/badge-needs-accessible-name.ts index cbc35ab..089f413 100644 --- a/lib/rules/badge-needs-accessible-name.js +++ b/lib/rules/badge-needs-accessible-name.ts @@ -1,19 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -var elementType = require("jsx-ast-utils").elementType; -const { getPropValue, getProp } = require("jsx-ast-utils"); -const { hasTextContentChild } = require("../util/hasTextContentChild"); -var hasProp = require("jsx-ast-utils").hasProp; +import { AST_NODE_TYPES, ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType, hasProp } from "jsx-ast-utils"; +import { getPropValue, getProp } from "jsx-ast-utils"; +import { hasTextContentChild } from "../util/hasTextContentChild"; +import { JSXAttribute, JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -34,8 +33,8 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXElement(node) { - const openingElement = node.openingElement; + JSXElement(node: TSESTree.JSXElement) { + const openingElement = node.openingElement as JSXOpeningElement; // If it's not a Badge component, return early if (elementType(openingElement) !== "Badge") { @@ -53,13 +52,13 @@ module.exports = { const hasIconProp = hasProp(openingElement.attributes, "icon"); if (hasIconProp) { - const iconProp = getProp(openingElement.attributes, "icon"); + const iconProp = getProp(openingElement.attributes, "icon") as TSESTree.JSXAttribute; - if (iconProp) { - const iconElement = iconProp.value.expression; + if (iconProp && iconProp.value && iconProp.value.type === AST_NODE_TYPES.JSXExpressionContainer) { + const iconElement = iconProp.value.expression as TSESTree.JSXElement; // Check if the icon has an aria-label - const ariaLabelAttr = hasProp(iconElement.openingElement.attributes, "aria-label"); + const ariaLabelAttr = hasProp(iconElement.openingElement.attributes as JSXAttribute[], "aria-label"); // Report an error if aria-label is missing if (!ariaLabelAttr) { @@ -76,8 +75,9 @@ module.exports = { } // Simplified logic to check for a color-only Badge (no icon, no text) + const roleProp = getProp(openingElement.attributes, "role"); const hasColorProp = hasProp(openingElement.attributes, "color"); - const hasRole = getPropValue(getProp(openingElement.attributes, "role")) === "img"; + const hasRole = !!roleProp && getPropValue(roleProp) === "img"; const hasAriaLabel = hasProp(openingElement.attributes, "aria-label"); // If it's color-only, ensure it has role="img" and aria-label @@ -91,12 +91,14 @@ module.exports = { // Fix role by adding role="img" if (!hasRole) { - fixes.push(fixer.insertTextAfter(openingElement.name, ' role="img"')); + fixes.push(fixer.insertTextAfter((openingElement as TSESTree.JSXOpeningElement).name, ' role="img"')); } // Fix aria-label by adding aria-label="" if (!hasAriaLabel) { - fixes.push(fixer.insertTextAfter(openingElement.name, ' aria-label=""')); + fixes.push( + fixer.insertTextAfter((openingElement as TSESTree.JSXOpeningElement).name, ' aria-label=""') + ); } return fixes; @@ -112,5 +114,6 @@ module.exports = { } }; } -}; +}); +export default rule; diff --git a/lib/rules/breadcrumb-needs-labelling.js b/lib/rules/breadcrumb-needs-labelling.ts similarity index 76% rename from lib/rules/breadcrumb-needs-labelling.js rename to lib/rules/breadcrumb-needs-labelling.ts index c157e56..ee1f746 100644 --- a/lib/rules/breadcrumb-needs-labelling.js +++ b/lib/rules/breadcrumb-needs-labelling.ts @@ -1,18 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { hasAssociatedLabelViaAriaLabelledBy } from "../util/labelUtils"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -25,16 +25,15 @@ module.exports = { recommended: false, url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a Breadcrumb, return - if (elementType(node) !== "Breadcrumb") { + if (elementType(node as JSXOpeningElement) !== "Breadcrumb") { return; } @@ -54,5 +53,6 @@ module.exports = { } }; } -}; +}); +export default rule; diff --git a/lib/rules/buttons/compound-button-needs-labelling.js b/lib/rules/buttons/compound-button-needs-labelling.ts similarity index 76% rename from lib/rules/buttons/compound-button-needs-labelling.js rename to lib/rules/buttons/compound-button-needs-labelling.ts index 14db29f..e4cdd46 100644 --- a/lib/rules/buttons/compound-button-needs-labelling.js +++ b/lib/rules/buttons/compound-button-needs-labelling.ts @@ -1,19 +1,20 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../../util/hasNonEmptyProp"); -const { hasToolTipParent } = require("../../util/hasTooltipParent"); -const { hasTextContentChild } = require("../../util/hasTextContentChild"); -const { hasAssociatedLabelViaAriaLabelledBy } = require("../../util/labelUtils"); -var elementType = require("jsx-ast-utils").elementType; +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../../util/hasNonEmptyProp"; +import { hasToolTipParent } from "../../util/hasTooltipParent"; +import { hasTextContentChild } from "../../util/hasTextContentChild"; +import { hasAssociatedLabelViaAriaLabelledBy } from "../../util/labelUtils"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -25,7 +26,7 @@ module.exports = { docs: { description: "Accessibility: Compound buttons must have accessible labelling: title, aria-label, aria-labelledby, aria-describedby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -34,11 +35,11 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXElement(node) { + JSXElement(node: TSESTree.JSXElement) { const openingElement = node.openingElement; // if it is not a Compound button, return - if (elementType(openingElement) !== "CompoundButton") { + if (elementType(openingElement as JSXOpeningElement) !== "CompoundButton") { return; } @@ -65,4 +66,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/buttons/image-button-missing-aria.js b/lib/rules/buttons/image-button-missing-aria.ts similarity index 74% rename from lib/rules/buttons/image-button-missing-aria.js rename to lib/rules/buttons/image-button-missing-aria.ts index 06fad1c..9cd6ff5 100644 --- a/lib/rules/buttons/image-button-missing-aria.js +++ b/lib/rules/buttons/image-button-missing-aria.ts @@ -1,21 +1,21 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../../util/hasNonEmptyProp"); -const { hasToolTipParent } = require("../../util/hasTooltipParent"); -const { hasTextContentChild } = require("../../util/hasTextContentChild"); -const { hasAssociatedLabelViaAriaLabelledBy } = require("../../util/labelUtils"); -const { applicableComponents } = require("../../applicableComponents/buttonBasedComponents"); -var hasProp = require("jsx-ast-utils").hasProp; -var elementType = require("jsx-ast-utils").elementType; +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType, hasProp } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../../util/hasNonEmptyProp"; +import { hasToolTipParent } from "../../util/hasTooltipParent"; +import { hasTextContentChild } from "../../util/hasTextContentChild"; +import { hasAssociatedLabelViaAriaLabelledBy } from "../../util/labelUtils"; +import { applicableComponents } from "../../applicableComponents/buttonBasedComponents"; +import { JSXAttribute, JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -27,7 +27,7 @@ module.exports = { docs: { description: "Accessibility: Image buttons must have accessible labelling: title, aria-label, aria-labelledby, aria-describedby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -36,16 +36,16 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXElement(node) { + JSXElement(node: TSESTree.JSXElement) { const openingElement = node.openingElement; // if it is not a button, return - if (!applicableComponents.includes(elementType(openingElement))) { + if (!applicableComponents.includes(elementType(openingElement as JSXOpeningElement))) { return; } // if it is not an icon button, return - if (!hasProp(openingElement.attributes, "icon")) { + if (!hasProp(openingElement.attributes as JSXAttribute[], "icon")) { return; } @@ -77,4 +77,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/buttons/no-empty-buttons.js b/lib/rules/buttons/no-empty-buttons.ts similarity index 72% rename from lib/rules/buttons/no-empty-buttons.js rename to lib/rules/buttons/no-empty-buttons.ts index a48815d..ec2158f 100644 --- a/lib/rules/buttons/no-empty-buttons.js +++ b/lib/rules/buttons/no-empty-buttons.ts @@ -1,19 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasTextContentChild } = require("../../util/hasTextContentChild"); -const { hasNonEmptyProp } = require("../../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -var hasProp = require("jsx-ast-utils").hasProp; +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType, hasProp } from "jsx-ast-utils"; +import { hasTextContentChild } from "../../util/hasTextContentChild"; +import { hasNonEmptyProp } from "../../util/hasNonEmptyProp"; +import { JSXAttribute, JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ const allowedComponents = ["Button", "ToggleButton", "SplitButton", "MenuButton", "CompoundButton"]; -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the lint rule messages: { @@ -24,7 +24,7 @@ module.exports = { // docs for the rule docs: { description: `Accessibility: ${allowedComponents.join(", ")} must either text content or icon or child component`, - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] // no options @@ -33,11 +33,11 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXElement(node) { + JSXElement(node: TSESTree.JSXElement) { const openingElement = node.openingElement; // if it is not a button, return - if (!allowedComponents.includes(elementType(openingElement))) { + if (!allowedComponents.includes(elementType(openingElement as JSXOpeningElement))) { return; } @@ -45,12 +45,15 @@ module.exports = { if (hasTextContentChild(node)) return; // if there is icon prop, return - if (hasProp(openingElement.attributes, "icon")) { + if (hasProp(openingElement.attributes as JSXAttribute[], "icon")) { return; } // if split button has secondary content, return - if (elementType(openingElement) === "CompoundButton" && hasNonEmptyProp(openingElement.attribute, "secondaryContent")) { + if ( + elementType(openingElement as JSXOpeningElement) === "CompoundButton" && + hasNonEmptyProp(openingElement.attributes, "secondaryContent") + ) { return; } @@ -66,4 +69,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/checkbox-needs-labelling.js b/lib/rules/checkbox-needs-labelling.ts similarity index 75% rename from lib/rules/checkbox-needs-labelling.js rename to lib/rules/checkbox-needs-labelling.ts index 33f776c..e16eea9 100644 --- a/lib/rules/checkbox-needs-labelling.js +++ b/lib/rules/checkbox-needs-labelling.ts @@ -1,18 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { elementType } from "jsx-ast-utils"; +import { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } from "../util/labelUtils"; +import { hasFieldParent } from "../util/hasFieldParent"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -24,7 +25,7 @@ module.exports = { docs: { // DONE description: "Accessibility: Checkbox without label must have an accessible and visual label: aria-labelledby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -33,9 +34,9 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a Checkbox, return - if (elementType(node) !== "Checkbox") { + if (elementType(node as JSXOpeningElement) !== "Checkbox") { return; } @@ -58,4 +59,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/combobox-needs-labelling.js b/lib/rules/combobox-needs-labelling.ts similarity index 75% rename from lib/rules/combobox-needs-labelling.js rename to lib/rules/combobox-needs-labelling.ts index 919ac9a..a5d2387 100644 --- a/lib/rules/combobox-needs-labelling.js +++ b/lib/rules/combobox-needs-labelling.ts @@ -1,19 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } from "../util/labelUtils"; +import { hasFieldParent } from "../util/hasFieldParent"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -26,16 +26,15 @@ module.exports = { recommended: false, url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a Combobox, return - if (elementType(node) !== "Combobox") { + if (elementType(node as JSXOpeningElement) !== "Combobox") { return; } @@ -58,5 +57,6 @@ module.exports = { } }; } -}; +}); +export default rule; diff --git a/lib/rules/dialogbody-needs-title-content-and-actions.js b/lib/rules/dialogbody-needs-title-content-and-actions.js deleted file mode 100644 index 62f09b9..0000000 --- a/lib/rules/dialogbody-needs-title-content-and-actions.js +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -"use strict"; - -//------------------------------------------------------------------------------ -// Rule Definition -//------------------------------------------------------------------------------ - -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { - meta: { - messages: { - dialogBodyOneTitleOneContentOneFooter: "ensure DialogBody has exactly one header,one content and one footer" - }, - type: "problem", // `problem`, `suggestion`, or `layout` - docs: { - description: "A DialogBody should have a header(DialogTitle), content(DialogContent), and footer(DialogActions)", - recommended: true, - url: "https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/" // URL to the documentation page for this rule - }, - fixable: null, // Or `code` or `whitespace` - schema: [] // Add a schema if the rule has options - }, - - create(context) { - return { - JSXOpeningElement(node) { - if (node.name.name !== "DialogBody") { - return; - } - - const children = node.parent.children.filter(child => child.type === "JSXElement"); - - const hasOneTitle = children.filter(child => child.openingElement.name.name === "DialogTitle").length === 1; - - const hasOneContnet = children.filter(child => child.openingElement.name.name === "DialogContent").length === 1; - - const hasOneAction = children.filter(child => child.openingElement.name.name === "DialogActions").length === 1; - - if (!hasOneTitle || !hasOneContnet || !hasOneAction || children.length !== 3) { - context.report({ - node, - messageId: "dialogBodyOneTitleOneContentOneFooter" - }); - } - } - }; - } -}; diff --git a/lib/rules/dialogbody-needs-title-content-and-actions.ts b/lib/rules/dialogbody-needs-title-content-and-actions.ts new file mode 100644 index 0000000..a9adaa1 --- /dev/null +++ b/lib/rules/dialogbody-needs-title-content-and-actions.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { AST_NODE_TYPES, ESLintUtils, TSESTree } from "@typescript-eslint/utils"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], + meta: { + messages: { + dialogBodyOneTitleOneContentOneFooter: "ensure DialogBody has exactly one header,one content and one footer" + }, + type: "problem", // `problem`, `suggestion`, or `layout` + docs: { + description: "A DialogBody should have a header(DialogTitle), content(DialogContent), and footer(DialogActions)", + recommended: "strict", + url: "https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/" // URL to the documentation page for this rule + }, + schema: [] // Add a schema if the rule has options + }, + + create(context) { + return { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { + if (node.name.type === AST_NODE_TYPES.JSXIdentifier && node.name.name !== "DialogBody") { + return; + } + + const children = + node.parent && + node.parent.type === AST_NODE_TYPES.JSXElement && + node.parent.children.filter(child => child.type === "JSXElement"); + + if (children) { + const hasOneTitle = + children.filter( + child => + child.openingElement.name.type === AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "DialogTitle" + ).length === 1; + + const hasOneContnet = + children.filter( + child => + child.openingElement.name.type === AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "DialogContent" + ).length === 1; + + const hasOneAction = + children.filter( + child => + child.openingElement.name.type === AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "DialogActions" + ).length === 1; + + if (!hasOneTitle || !hasOneContnet || !hasOneAction || children.length !== 3) { + context.report({ + node, + messageId: "dialogBodyOneTitleOneContentOneFooter" + }); + } + } + } + }; + } +}); + +export default rule; diff --git a/lib/rules/dialogsurface-needs-aria.js b/lib/rules/dialogsurface-needs-aria.js deleted file mode 100644 index b1a71da..0000000 --- a/lib/rules/dialogsurface-needs-aria.js +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -"use strict"; - -const { hasAssociatedAriaText } = require("../util/labelUtils"); -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const { hasTextContentChild } = require("../util/hasTextContentChild"); -var elementType = require("jsx-ast-utils").elementType; - -//------------------------------------------------------------------------------ -// Rule Definition -//------------------------------------------------------------------------------ - -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { - meta: { - // possible error messages for the rule - messages: { - missingAriaOnDialogSurface: "DialogueSurface need accessible labelling: aria-describedby on DialogueSurface and aria-label or aria-labelledby(if DialogueTitle is missing)" - }, - // "problem" means the rule is identifying code that either will cause an error or may cause a confusing behavior: https://eslint.org/docs/latest/developer-guide/working-with-rules - type: "problem", - // docs for the rule - docs: { - description: "DialogueSurface need accessible labelling: aria-describedby on DialogueSurface and aria-label or aria-labelledby(if DialogueTitle is missing)", - recommended: true, - url: "https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/" // URL to the documentation page for this rule - }, - schema: [] - }, - - create(context) { - return { - // visitor functions for different types of nodes - JSXOpeningElement(node) { - - // if it is not a DialogSurface, return - if (elementType(node) !== "DialogSurface") { - return; - } - - // determine if DialogSurface as aria-describedby - const hasAriaDescribedBy = hasAssociatedAriaText(node, context, "aria-describedby"); - - // find DialogBody Component - const dialogueSurfaceChildren = node.parent.children.filter(child => child.type === "JSXElement"); - - const DialogBodyNode = dialogueSurfaceChildren.find(child => child.openingElement.name.name === "DialogBody"); - - - // find DialogTitle inside DialogBody Component - const dialogueBodyChildren = DialogBodyNode && DialogBodyNode.children.filter(child => child.type === "JSXElement"); - - const DialogTitleNode = dialogueBodyChildren && dialogueBodyChildren.find(child => child.openingElement.name.name === "DialogTitle"); - - // determine if DialogueText has any text content - const hasDialogTitleText = DialogTitleNode && hasTextContentChild(DialogTitleNode); - - // determine if DialogueText or aria-label is present - const hasTitleOrAriaLabelledBy = hasDialogTitleText || hasNonEmptyProp(node.attributes, "aria-label") || hasAssociatedAriaText(node, context, "aria-labelledby"); - - // if the DialogSurface has aria labelling and description, return - if (hasAriaDescribedBy && hasTitleOrAriaLabelledBy) { - return; - } - - context.report({ - node, - messageId: `missingAriaOnDialogSurface` - }); - } - }; - } -}; - diff --git a/lib/rules/dialogsurface-needs-aria.ts b/lib/rules/dialogsurface-needs-aria.ts new file mode 100644 index 0000000..dcb59ed --- /dev/null +++ b/lib/rules/dialogsurface-needs-aria.ts @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { AST_NODE_TYPES, ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasAssociatedAriaText } from "../util/labelUtils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { hasTextContentChild } from "../util/hasTextContentChild"; +import { JSXOpeningElement } from "estree-jsx"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], + meta: { + // possible error messages for the rule + messages: { + missingAriaOnDialogSurface: + "DialogueSurface need accessible labelling: aria-describedby on DialogueSurface and aria-label or aria-labelledby(if DialogueTitle is missing)" + }, + // "problem" means the rule is identifying code that either will cause an error or may cause a confusing behavior: https://eslint.org/docs/latest/developer-guide/working-with-rules + type: "problem", + // docs for the rule + docs: { + description: + "DialogueSurface need accessible labelling: aria-describedby on DialogueSurface and aria-label or aria-labelledby(if DialogueTitle is missing)", + recommended: "strict", + url: "https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/" // URL to the documentation page for this rule + }, + schema: [] + }, + + create(context) { + return { + // visitor functions for different types of nodes + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { + // if it is not a DialogSurface, return + if (elementType(node as JSXOpeningElement) !== "DialogSurface") { + return; + } + + // determine if DialogSurface as aria-describedby + const hasAriaDescribedBy = hasAssociatedAriaText(node, context, "aria-describedby"); + + // find DialogBody Component + const dialogueSurfaceChildren = + node.parent && + node.parent.type === AST_NODE_TYPES.JSXElement && + node.parent.children.filter(child => child.type === "JSXElement"); + + if (dialogueSurfaceChildren) { + const DialogBodyNode = dialogueSurfaceChildren.find( + child => + child.openingElement.name.type === AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "DialogBody" + ); + + // find DialogTitle inside DialogBody Component + const dialogueBodyChildren = DialogBodyNode && DialogBodyNode.children.filter(child => child.type === "JSXElement"); + + const DialogTitleNode = + dialogueBodyChildren && + dialogueBodyChildren.find( + child => + child.openingElement.name.type === AST_NODE_TYPES.JSXIdentifier && + child.openingElement.name.name === "DialogTitle" + ); + + // determine if DialogueText has any text content + const hasDialogTitleText = DialogTitleNode && hasTextContentChild(DialogTitleNode); + + // determine if DialogueText or aria-label is present + const hasTitleOrAriaLabelledBy = + hasDialogTitleText || + hasNonEmptyProp(node.attributes, "aria-label") || + hasAssociatedAriaText(node, context, "aria-labelledby"); + + // if the DialogSurface has aria labelling and description, return + if (hasAriaDescribedBy && hasTitleOrAriaLabelledBy) { + return; + } + + context.report({ + node, + messageId: `missingAriaOnDialogSurface` + }); + } + } + }; + } +}); + +export default rule; diff --git a/lib/rules/dropdown-needs-labelling.js b/lib/rules/dropdown-needs-labelling.ts similarity index 77% rename from lib/rules/dropdown-needs-labelling.js rename to lib/rules/dropdown-needs-labelling.ts index f87e46b..8141c82 100644 --- a/lib/rules/dropdown-needs-labelling.js +++ b/lib/rules/dropdown-needs-labelling.ts @@ -1,17 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, hasAssociatedLabelViaHtmlFor, isInsideLabelTag } = require("../util/labelUtils"); -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasAssociatedLabelViaAriaLabelledBy, hasAssociatedLabelViaHtmlFor, isInsideLabelTag } from "../util/labelUtils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -22,8 +23,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Dropdown menu must have an id and it needs to be linked via htmlFor of a Label", - recommended: true, - url: null + recommended: "strict" }, schema: [] }, @@ -32,9 +32,9 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a Dropdown, return - if (elementType(node) !== "Dropdown") { + if (elementType(node as JSXOpeningElement) !== "Dropdown") { return; } @@ -59,4 +59,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/input-components-require-accessible-name.js b/lib/rules/input-components-require-accessible-name.ts similarity index 74% rename from lib/rules/input-components-require-accessible-name.js rename to lib/rules/input-components-require-accessible-name.ts index 7068829..9fa0c88 100644 --- a/lib/rules/input-components-require-accessible-name.js +++ b/lib/rules/input-components-require-accessible-name.ts @@ -1,19 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { elementType } = require("jsx-ast-utils"); - -const { isInsideLabelTag, hasAssociatedLabelViaHtmlFor, hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); -const { applicableComponents } = require("../applicableComponents/inputBasedComponents"); +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { isInsideLabelTag, hasAssociatedLabelViaHtmlFor, hasAssociatedLabelViaAriaLabelledBy } from "../util/labelUtils"; +import { hasFieldParent } from "../util/hasFieldParent"; +import { applicableComponents } from "../applicableComponents/inputBasedComponents"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -26,7 +26,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Input fields must have accessible labelling: aria-label, aria-labelledby or an associated label", - recommended: true, + recommended: "strict", url: "https://www.w3.org/WAI/tutorials/forms/labels/" // URL to the documentation page for this rule }, schema: [] @@ -35,9 +35,9 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a listed component, return - if (!applicableComponents.includes(elementType(node))) { + if (!applicableComponents.includes(elementType(node as JSXOpeningElement))) { return; } @@ -58,4 +58,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/link-missing-labelling.js b/lib/rules/link-missing-labelling.ts similarity index 81% rename from lib/rules/link-missing-labelling.js rename to lib/rules/link-missing-labelling.ts index 845e9ce..a086394 100644 --- a/lib/rules/link-missing-labelling.js +++ b/lib/rules/link-missing-labelling.ts @@ -1,27 +1,27 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { elementType } = require("jsx-ast-utils"); -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const { hasTextContentChild } = require("../util/hasTextContentChild"); -const { hasLabelledChildImage } = require("../util/hasLabelledChildImage"); -const { linkBasedComponents } = require("../applicableComponents/linkBasedComponents"); -const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { hasTextContentChild } from "../util/hasTextContentChild"; +import { hasLabelledChildImage } from "../util/hasLabelledChildImage"; +import { linkBasedComponents } from "../applicableComponents/linkBasedComponents"; +import { hasAssociatedLabelViaAriaLabelledBy } from "../util/labelUtils"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { type: "problem", docs: { description: "Accessibility: Image links must have an accessible name. Add either text content, labelling to the image or labelling to the link itself.", - recommended: true, + recommended: "strict", url: "https://www.w3.org/WAI/standards-guidelines/act/rules/c487ae/" // URL to the documentation page for this rule }, messages: { @@ -40,11 +40,11 @@ module.exports = { return { // visitor functions for different types of nodes - JSXElement(node) { + JSXElement(node: TSESTree.JSXElement) { const openingElement = node.openingElement; // if it's not a link based component, return - if (!linkBasedComponents.includes(elementType(openingElement))) { + if (!linkBasedComponents.includes(elementType(openingElement as JSXOpeningElement))) { return; } @@ -90,4 +90,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/menu-item-needs-labelling.js b/lib/rules/menu-item-needs-labelling.ts similarity index 74% rename from lib/rules/menu-item-needs-labelling.js rename to lib/rules/menu-item-needs-labelling.ts index 6bc4e2a..e1d2169 100644 --- a/lib/rules/menu-item-needs-labelling.js +++ b/lib/rules/menu-item-needs-labelling.ts @@ -1,20 +1,20 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); -const { hasTextContentChild } = require("../util/hasTextContentChild"); -const { hasToolTipParent } = require("../util/hasTooltipParent"); +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { hasAssociatedLabelViaAriaLabelledBy } from "../util/labelUtils"; +import { hasTextContentChild } from "../util/hasTextContentChild"; +import { hasToolTipParent } from "../util/hasTooltipParent"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -24,20 +24,19 @@ module.exports = { type: "problem", docs: { description: "Accessibility: MenuItem without label must have an accessible and visual label: aria-labelledby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, create(context) { return { // visitor functions for different types of nodes - JSXElement(node) { + JSXElement(node: TSESTree.JSXElement) { const openingElement = node.openingElement; // if it is not a MenuItem, return - if (elementType(openingElement) !== "MenuItem") { + if (elementType(openingElement as JSXOpeningElement) !== "MenuItem") { return; } @@ -59,5 +58,6 @@ module.exports = { } }; } -}; +}); +export default rule; diff --git a/lib/rules/no-empty-components.js b/lib/rules/no-empty-components.ts similarity index 81% rename from lib/rules/no-empty-components.js rename to lib/rules/no-empty-components.ts index b023967..6e4f61a 100644 --- a/lib/rules/no-empty-components.js +++ b/lib/rules/no-empty-components.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -var elementType = require("jsx-ast-utils").elementType; +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { JSXOpeningElement } from "estree-jsx"; +import { elementType } from "jsx-ast-utils"; //------------------------------------------------------------------------------ // Rule Definition @@ -11,8 +11,8 @@ var elementType = require("jsx-ast-utils").elementType; // Define an array of allowed component names const allowedComponents = ["Text", "Label", "Combobox", "Breadcrumb", "Dropdown", "Accordion", "AccordionItem", "AccordionPanel"]; -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the lint rule messages: { @@ -21,21 +21,19 @@ module.exports = { type: "problem", // `problem`, `suggestion`, or `layout` docs: { description: "FluentUI components should not be empty", - recommended: true, - url: null // URL to the documentation page for this rule + recommended: "strict" }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, // create (function) returns an object with methods that ESLint calls to “visit” nodes while traversing the abstract syntax tree create(context) { return { // visitor functions for different types of nodes - JSXElement(node) { + JSXElement(node: TSESTree.JSXElement) { const openingElement = node.openingElement; // if it is not a listed component, return - if (!allowedComponents.includes(elementType(openingElement))) { + if (!allowedComponents.includes(elementType(openingElement as JSXOpeningElement))) { return; } @@ -51,4 +49,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/progressbar-needs-labelling.js b/lib/rules/progressbar-needs-labelling.ts similarity index 84% rename from lib/rules/progressbar-needs-labelling.js rename to lib/rules/progressbar-needs-labelling.ts index a580aea..37ad191 100644 --- a/lib/rules/progressbar-needs-labelling.js +++ b/lib/rules/progressbar-needs-labelling.ts @@ -1,17 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasFieldParent } = require("../util/hasFieldParent"); -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const elementType = require("jsx-ast-utils").elementType; +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasFieldParent } from "../util/hasFieldParent"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -24,7 +25,7 @@ module.exports = { docs: { description: "Accessibility: Progressbar must have aria-valuemin, aria-valuemax, aria-valuenow, aria-describedby and either aria-label or aria-labelledby attributes", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -33,9 +34,9 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a ProgressBar, return - if (elementType(node) !== "ProgressBar") { + if (elementType(node as JSXOpeningElement) !== "ProgressBar") { return; } @@ -73,5 +74,6 @@ module.exports = { } }; } -}; +}); +export default rule; diff --git a/lib/rules/radio-button-missing-label.js b/lib/rules/radio-button-missing-label.ts similarity index 76% rename from lib/rules/radio-button-missing-label.js rename to lib/rules/radio-button-missing-label.ts index 9e76123..fa7c791 100644 --- a/lib/rules/radio-button-missing-label.js +++ b/lib/rules/radio-button-missing-label.ts @@ -1,18 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } from "../util/labelUtils"; +import { hasFieldParent } from "../util/hasFieldParent"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -24,7 +25,7 @@ module.exports = { docs: { // DONE description: "Accessibility: Radio button without label must have an accessible and visual label: aria-labelledby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -33,9 +34,9 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a Checkbox, return - if (elementType(node) !== "Radio") { + if (elementType(node as JSXOpeningElement) !== "Radio") { return; } @@ -59,4 +60,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/radiogroup-missing-label.js b/lib/rules/radiogroup-missing-label.ts similarity index 75% rename from lib/rules/radiogroup-missing-label.js rename to lib/rules/radiogroup-missing-label.ts index 9be7dc1..eb585f2 100644 --- a/lib/rules/radiogroup-missing-label.js +++ b/lib/rules/radiogroup-missing-label.ts @@ -1,18 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } from "../util/labelUtils"; +import { hasFieldParent } from "../util/hasFieldParent"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -24,7 +25,7 @@ module.exports = { docs: { // DONE description: "Accessibility: RadioGroup without label must have an accessible and visual label: aria-labelledby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -33,9 +34,9 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a Checkbox, return - if (elementType(node) !== "RadioGroup") { + if (elementType(node as JSXOpeningElement) !== "RadioGroup") { return; } @@ -59,4 +60,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/spin-button-needs-labelling.js b/lib/rules/spin-button-needs-labelling.ts similarity index 75% rename from lib/rules/spin-button-needs-labelling.js rename to lib/rules/spin-button-needs-labelling.ts index 181a57b..d6272f8 100644 --- a/lib/rules/spin-button-needs-labelling.js +++ b/lib/rules/spin-button-needs-labelling.ts @@ -1,17 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } from "../util/labelUtils"; +import { hasFieldParent } from "../util/hasFieldParent"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -22,7 +23,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: SpinButtons must have an accessible label", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -31,9 +32,9 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a SpinButton, return - if (elementType(node) !== "SpinButton") { + if (elementType(node as JSXOpeningElement) !== "SpinButton") { return; } @@ -55,4 +56,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/spin-button-unrecommended-labelling.js b/lib/rules/spin-button-unrecommended-labelling.ts similarity index 75% rename from lib/rules/spin-button-unrecommended-labelling.js rename to lib/rules/spin-button-unrecommended-labelling.ts index a713d83..e10b6c4 100644 --- a/lib/rules/spin-button-unrecommended-labelling.js +++ b/lib/rules/spin-button-unrecommended-labelling.ts @@ -1,17 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const { hasToolTipParent } = require("../util/hasTooltipParent"); -var elementType = require("jsx-ast-utils").elementType; +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { hasToolTipParent } from "../util/hasTooltipParent"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible suggestion messages for the rule messages: { @@ -22,7 +23,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Unrecommended accessibility labelling - SpinButton", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -31,9 +32,9 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a SpinButton, return - if (elementType(node) !== "SpinButton") { + if (elementType(node as JSXOpeningElement) !== "SpinButton") { return; } @@ -47,5 +48,6 @@ module.exports = { } }; } -}; +}); +export default rule; diff --git a/lib/rules/spinner-needs-labelling.js b/lib/rules/spinner-needs-labelling.ts similarity index 67% rename from lib/rules/spinner-needs-labelling.js rename to lib/rules/spinner-needs-labelling.ts index cc1dc58..5005cc6 100644 --- a/lib/rules/spinner-needs-labelling.js +++ b/lib/rules/spinner-needs-labelling.ts @@ -1,16 +1,17 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -const elementType = require("jsx-ast-utils").elementType; +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -21,7 +22,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Spinner must have either aria-label or label, aria-live and aria-busy attributes", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -30,15 +31,16 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a Spinner, return - if (elementType(node) !== "Spinner") { + if (elementType(node as JSXOpeningElement) !== "Spinner") { return; } - if (hasNonEmptyProp(node.attributes, "aria-busy") - && hasNonEmptyProp(node.attributes, "aria-live") - && (hasNonEmptyProp(node.attributes, "label") || hasNonEmptyProp(node.attributes, "aria-label")) + if ( + hasNonEmptyProp(node.attributes, "aria-busy") && + hasNonEmptyProp(node.attributes, "aria-live") && + (hasNonEmptyProp(node.attributes, "label") || hasNonEmptyProp(node.attributes, "aria-label")) ) { return; } @@ -51,5 +53,6 @@ module.exports = { } }; } -}; +}); +export default rule; diff --git a/lib/rules/switch-needs-labelling.js b/lib/rules/switch-needs-labelling.ts similarity index 74% rename from lib/rules/switch-needs-labelling.js rename to lib/rules/switch-needs-labelling.ts index f2e1d5b..648a6f3 100644 --- a/lib/rules/switch-needs-labelling.js +++ b/lib/rules/switch-needs-labelling.ts @@ -1,18 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; -const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } = require("../util/labelUtils"); -const { hasFieldParent } = require("../util/hasFieldParent"); +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag, hasAssociatedLabelViaHtmlFor } from "../util/labelUtils"; +import { hasFieldParent } from "../util/hasFieldParent"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -23,7 +24,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Switch must have an accessible label", - recommended: true, + recommended: "strict", url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule }, schema: [] @@ -32,9 +33,9 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a Switch, return - if (elementType(node) !== "Switch") { + if (elementType(node as JSXOpeningElement) !== "Switch") { return; } @@ -57,4 +58,6 @@ module.exports = { } }; } -}; +}); + +export default rule; diff --git a/lib/rules/toolbar-missing-aria.js b/lib/rules/toolbar-missing-aria.ts similarity index 73% rename from lib/rules/toolbar-missing-aria.js rename to lib/rules/toolbar-missing-aria.ts index f7438db..f725458 100644 --- a/lib/rules/toolbar-missing-aria.js +++ b/lib/rules/toolbar-missing-aria.ts @@ -1,18 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils"); -const { hasNonEmptyProp } = require("../util/hasNonEmptyProp"); -var elementType = require("jsx-ast-utils").elementType; +import { ESLintUtils, TSESTree } from "@typescript-eslint/utils"; +import { elementType } from "jsx-ast-utils"; +import { hasAssociatedLabelViaAriaLabelledBy } from "../util/labelUtils"; +import { hasNonEmptyProp } from "../util/hasNonEmptyProp"; +import { JSXOpeningElement } from "estree-jsx"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the rule messages: { @@ -23,7 +23,7 @@ module.exports = { // docs for the rule docs: { description: "Accessibility: Toolbars need accessible labelling: aria-label or aria-labelledby", - recommended: true, + recommended: "strict", url: "https://www.w3.org/WAI/tutorials/forms/labels/" // URL to the documentation page for this rule }, schema: [] @@ -32,9 +32,9 @@ module.exports = { create(context) { return { // visitor functions for different types of nodes - JSXOpeningElement(node) { + JSXOpeningElement(node: TSESTree.JSXOpeningElement) { // if it is not a Toolbar, return - if (elementType(node) !== "Toolbar") { + if (elementType(node as JSXOpeningElement) !== "Toolbar") { return; } @@ -50,5 +50,6 @@ module.exports = { } }; } -}; +}); +export default rule; diff --git a/lib/rules/tooltip-not-recommended.js b/lib/rules/tooltip-not-recommended.ts similarity index 78% rename from lib/rules/tooltip-not-recommended.js rename to lib/rules/tooltip-not-recommended.ts index 6c12a06..b2111c9 100644 --- a/lib/rules/tooltip-not-recommended.js +++ b/lib/rules/tooltip-not-recommended.ts @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - -var elementType = require("jsx-ast-utils").elementType; -const { hasToolTipParent } = require("../util/hasTooltipParent"); +import {ESLintUtils, TSESTree} from '@typescript-eslint/utils'; +import { elementType } from "jsx-ast-utils"; +import { hasToolTipParent } from "../util/hasTooltipParent"; +import { JSXOpeningElement } from 'estree-jsx'; //------------------------------------------------------------------------------ // Rule Definition @@ -12,8 +12,8 @@ const { hasToolTipParent } = require("../util/hasTooltipParent"); // Define an array of allowed component names const allowedComponents = ["MenuItem", "SpinButton"]; -/** @type {import('eslint').Rule.RuleModule} */ -module.exports = { +const rule = ESLintUtils.RuleCreator.withoutDocs({ + defaultOptions: [], meta: { // possible error messages for the lint rule messages: { @@ -22,21 +22,19 @@ module.exports = { type: "suggestion", // `problem`, `suggestion`, or `layout` docs: { description: `Accessibility: Prefer text content or aria over a tooltip for these components ${allowedComponents.join(", ")}`, - recommended: true, - url: null // URL to the documentation page for this rule + recommended: 'strict', }, - fixable: null, // Or `code` or `whitespace` schema: [] // Add a schema if the rule has options }, // create (function) returns an object with methods that ESLint calls to “visit” nodes while traversing the abstract syntax tree create(context) { return { // visitor functions for different types of nodes - JSXElement(node) { + JSXElement(node: TSESTree.JSXElement) { const openingElement = node.openingElement; // if it is not a listed component, return - if (!allowedComponents.includes(elementType(openingElement))) { + if (!allowedComponents.includes(elementType(openingElement as JSXOpeningElement))) { return; } @@ -50,5 +48,8 @@ module.exports = { } }; } -}; +}); + + +export default rule; \ No newline at end of file diff --git a/lib/util/hasLabelledChildImage.js b/lib/util/hasLabelledChildImage.js index b15cdeb..9b5684d 100644 --- a/lib/util/hasLabelledChildImage.js +++ b/lib/util/hasLabelledChildImage.js @@ -21,12 +21,7 @@ function hasLabelledChildImage(node) { // Check if there is an accessible image const hasAccessibleImage = flattenChildren(node).some(child => { - console.log( - "mergedImageComponents.includes(child.openingElement.name.name)::: ", - mergedImageComponents.includes(child.openingElement.name.name) - ); if (child.type === "JSXElement" && mergedImageComponents.includes(child.openingElement.name.name)) { - console.log("here 3"); return hasProp(child.openingElement.attributes, "aria-hidden") || getPropValue(child.openingElement.attributes, "alt") ? false : hasNonEmptyProp(child.openingElement.attributes, "title") || diff --git a/package-lock.json b/package-lock.json index 481f21d..55b858a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,9 +14,11 @@ "requireindex": "^1.2.0" }, "devDependencies": { + "@types/chai": "^4.3.19", "@types/eslint": "=7.2.10", "@types/estree": "^1.0.5", "@types/estree-jsx": "^1.0.5", + "@types/jest": "^29.5.13", "@types/jsx-ast-utils": "^3.3.1", "@types/node": "^22.5.5", "@typescript-eslint/eslint-plugin": "^8.6.0", @@ -31,7 +33,6 @@ "jest": "^29.7.0", "markdownlint": "^0.28.1", "markdownlint-cli": "^0.33.0", - "mocha": "^10.0.0", "npm-run-all": "^4.1.5", "prettier": "2.8.4", "ts-jest": "^29.2.5", @@ -1233,6 +1234,12 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/chai": { + "version": "4.3.19", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.19.tgz", + "integrity": "sha512-2hHHvQBVE2FiSK4eN0Br6snX9MtolHaTo/batnLjlGRhoQzlCL61iVpxoqO7SfFyOw+P/pwv+0zNHzKoGWz9Cw==", + "dev": true + }, "node_modules/@types/eslint": { "version": "7.2.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.10.tgz", @@ -1291,6 +1298,16 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/jest": { + "version": "29.5.13", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.13.tgz", + "integrity": "sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -2009,15 +2026,6 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -2263,15 +2271,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/boolean": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", @@ -2312,12 +2311,6 @@ "node": ">=8" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, "node_modules/browserslist": { "version": "4.23.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", @@ -2536,33 +2529,6 @@ "node": "*" } }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -2584,17 +2550,6 @@ "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", "dev": true }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -2733,18 +2688,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/dedent": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", @@ -2819,15 +2762,6 @@ "node": ">=8" } }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -3673,15 +3607,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -4039,15 +3964,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -4206,18 +4122,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -4352,15 +4256,6 @@ "node": ">=8" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -4445,18 +4340,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -5366,22 +5249,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/loupe": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", @@ -5664,85 +5531,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -6299,15 +6087,6 @@ } ] }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -6340,18 +6119,6 @@ "node": ">=4" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -6526,26 +6293,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/safe-regex-test": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", @@ -6568,15 +6315,6 @@ "semver": "bin/semver" } }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -7228,12 +6966,6 @@ "node": ">=0.10.0" } }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -7318,48 +7050,6 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 3c64585..85f2f91 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "lint": "npm-run-all \"lint:*\"", "lint:eslint-docs": "npm-run-all \"update:eslint-docs -- --check\"", "lint:js": "eslint .", - "test": "mocha tests --recursive && jest", + "test": "jest", "lint:docs": "markdownlint **/*.md", "update:eslint-docs": "eslint-doc-generator", "fix:md": "npm run lint:docs -- --fix", @@ -52,9 +52,11 @@ "requireindex": "^1.2.0" }, "devDependencies": { + "@types/chai": "^4.3.19", "@types/eslint": "=7.2.10", "@types/estree": "^1.0.5", "@types/estree-jsx": "^1.0.5", + "@types/jest": "^29.5.13", "@types/jsx-ast-utils": "^3.3.1", "@types/node": "^22.5.5", "@typescript-eslint/eslint-plugin": "^8.6.0", @@ -69,7 +71,6 @@ "jest": "^29.7.0", "markdownlint": "^0.28.1", "markdownlint-cli": "^0.33.0", - "mocha": "^10.0.0", "npm-run-all": "^4.1.5", "prettier": "2.8.4", "ts-jest": "^29.2.5", diff --git a/tests/lib/rules/accordion-header-needs-labelling.js b/tests/lib/rules/accordion-header-needs-labelling.test.ts similarity index 86% rename from tests/lib/rules/accordion-header-needs-labelling.js rename to tests/lib/rules/accordion-header-needs-labelling.test.ts index bb2310d..93e4304 100644 --- a/tests/lib/rules/accordion-header-needs-labelling.js +++ b/tests/lib/rules/accordion-header-needs-labelling.test.ts @@ -1,31 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const RuleTester = require("eslint").RuleTester; - -const rule = require("../../../lib/rules/accordion-header-needs-labelling"); - -RuleTester.setDefaultConfig({ - parserOptions: { - ecmaVersion: 6, - ecmaFeatures: { - jsx: true - } - } -}); +import { Rule } from "eslint"; +import ruleTester from "./helper/ruleTester"; +import rule from "../../../lib/rules/accordion-header-needs-labelling"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("accordion-header-needs-labelling", rule, { +ruleTester.run("accordion-header-needs-labelling", rule as unknown as Rule.RuleModule, { valid: [ "Accordion Header 1", "}>Accordion Header 1", diff --git a/tests/lib/rules/accordion-item-needs-header-and-panel.js b/tests/lib/rules/accordion-item-needs-header-and-panel.test.ts similarity index 81% rename from tests/lib/rules/accordion-item-needs-header-and-panel.js rename to tests/lib/rules/accordion-item-needs-header-and-panel.test.ts index 7037402..2392eda 100644 --- a/tests/lib/rules/accordion-item-needs-header-and-panel.js +++ b/tests/lib/rules/accordion-item-needs-header-and-panel.test.ts @@ -1,30 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const rule = require("../../../lib/rules/accordion-item-needs-header-and-panel"), - RuleTester = require("eslint").RuleTester; - -RuleTester.setDefaultConfig({ - parserOptions: { - ecmaVersion: 6, - ecmaFeatures: { - jsx: true - } - } -}); +import { Rule } from "eslint"; +import ruleTester from "./helper/ruleTester"; +import rule from "../../../lib/rules/accordion-item-needs-header-and-panel"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("accordion-item-needs-header-and-panel", rule, { +ruleTester.run("accordion-item-needs-header-and-panel", rule as unknown as Rule.RuleModule, { valid: [ `Accordion Header 1
Accordion Panel 1
` ], diff --git a/tests/lib/rules/avatar-needs-name.js b/tests/lib/rules/avatar-needs-name.test.ts similarity index 82% rename from tests/lib/rules/avatar-needs-name.js rename to tests/lib/rules/avatar-needs-name.test.ts index 1769a78..f307c82 100644 --- a/tests/lib/rules/avatar-needs-name.js +++ b/tests/lib/rules/avatar-needs-name.test.ts @@ -1,31 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const RuleTester = require("eslint").RuleTester; - -const rule = require("../../../lib/rules/avatar-needs-name"); - -RuleTester.setDefaultConfig({ - parserOptions: { - ecmaVersion: 6, - ecmaFeatures: { - jsx: true - } - } -}); +import { Rule } from "eslint"; +import ruleTester from "./helper/ruleTester"; +import rule from "../../../lib/rules/avatar-needs-name"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("avatar-needs-name", rule, { +ruleTester.run("avatar-needs-name", rule as unknown as Rule.RuleModule, { valid: [ // give me some code that won't trigger a warning '', diff --git a/tests/lib/rules/avoid-using-aria-describedby-for-primary-labelling.js b/tests/lib/rules/avoid-using-aria-describedby-for-primary-labelling.test.ts similarity index 83% rename from tests/lib/rules/avoid-using-aria-describedby-for-primary-labelling.js rename to tests/lib/rules/avoid-using-aria-describedby-for-primary-labelling.test.ts index 3812535..57c26d0 100644 --- a/tests/lib/rules/avoid-using-aria-describedby-for-primary-labelling.js +++ b/tests/lib/rules/avoid-using-aria-describedby-for-primary-labelling.test.ts @@ -1,30 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const rule = require("../../../lib/rules/avoid-using-aria-describedby-for-primary-labelling"), - RuleTester = require("eslint").RuleTester; - -RuleTester.setDefaultConfig({ - parserOptions: { - ecmaVersion: 6, - ecmaFeatures: { - jsx: true - } - } -}); +import { Rule } from "eslint"; +import ruleTester from "./helper/ruleTester"; +import rule from "../../../lib/rules/avoid-using-aria-describedby-for-primary-labelling"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("avoid-using-aria-describedby-for-primary-labelling", rule, { +ruleTester.run("avoid-using-aria-describedby-for-primary-labelling", rule as unknown as Rule.RuleModule, { valid: [ '<>', diff --git a/tests/lib/rules/badge-needs-accessible-name.js b/tests/lib/rules/badge-needs-accessible-name.test.ts similarity index 85% rename from tests/lib/rules/badge-needs-accessible-name.js rename to tests/lib/rules/badge-needs-accessible-name.test.ts index b47c1ae..fa7db40 100644 --- a/tests/lib/rules/badge-needs-accessible-name.js +++ b/tests/lib/rules/badge-needs-accessible-name.test.ts @@ -1,30 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const rule = require("../../../lib/rules/badge-needs-accessible-name"), - RuleTester = require("eslint").RuleTester; - -RuleTester.setDefaultConfig({ - parserOptions: { - ecmaVersion: 6, - ecmaFeatures: { - jsx: true - } - } -}); +import { Rule } from "eslint"; +import ruleTester from "./helper/ruleTester"; +import rule from "../../../lib/rules/badge-needs-accessible-name"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("badge-needs-accessible-name", rule, { +ruleTester.run("badge-needs-accessible-name", rule as unknown as Rule.RuleModule, { valid: [ ``, `} />`, @@ -69,4 +58,3 @@ ruleTester.run("badge-needs-accessible-name", rule, { } ] }); - diff --git a/tests/lib/rules/breadcrumb-needs-labelling.js b/tests/lib/rules/breadcrumb-needs-labelling.test.ts similarity index 78% rename from tests/lib/rules/breadcrumb-needs-labelling.js rename to tests/lib/rules/breadcrumb-needs-labelling.test.ts index 5d48c81..802981e 100644 --- a/tests/lib/rules/breadcrumb-needs-labelling.js +++ b/tests/lib/rules/breadcrumb-needs-labelling.test.ts @@ -1,30 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const rule = require("../../../lib/rules/breadcrumb-needs-labelling"), - RuleTester = require("eslint").RuleTester; - -RuleTester.setDefaultConfig({ - parserOptions: { - ecmaVersion: 6, - ecmaFeatures: { - jsx: true - } - } -}); +import { Rule } from "eslint"; +import ruleTester from "./helper/ruleTester"; +import rule from "../../../lib/rules/breadcrumb-needs-labelling"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("breadcrumb-needs-labelling", rule, { +ruleTester.run("breadcrumb-needs-labelling", rule as unknown as Rule.RuleModule, { valid: [ // give me some code that won't trigger a warning '', diff --git a/tests/lib/rules/buttons/compound-button-needs-labelling.js b/tests/lib/rules/buttons/compound-button-needs-labelling.test.ts similarity index 88% rename from tests/lib/rules/buttons/compound-button-needs-labelling.js rename to tests/lib/rules/buttons/compound-button-needs-labelling.test.ts index 022f88a..6c00dca 100644 --- a/tests/lib/rules/buttons/compound-button-needs-labelling.js +++ b/tests/lib/rules/buttons/compound-button-needs-labelling.test.ts @@ -1,21 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ - -const rule = require("../../../../lib/rules/buttons/compound-button-needs-labelling"), - RuleTester = require("eslint").RuleTester; +import { Rule } from "eslint"; +import ruleTester from "../helper/ruleTester"; +import rule from "../../../../lib/rules/buttons/compound-button-needs-labelling"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("compound-button-needs-labelling", rule, { +ruleTester.run("compound-button-needs-labelling", rule as unknown as Rule.RuleModule, { valid: [ '}>', "Example", diff --git a/tests/lib/rules/buttons/image-button-missing-aria.js b/tests/lib/rules/buttons/image-button-missing-aria.test.ts similarity index 91% rename from tests/lib/rules/buttons/image-button-missing-aria.js rename to tests/lib/rules/buttons/image-button-missing-aria.test.ts index fa46ffa..eedca93 100644 --- a/tests/lib/rules/buttons/image-button-missing-aria.js +++ b/tests/lib/rules/buttons/image-button-missing-aria.test.ts @@ -1,21 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const rule = require("../../../../lib/rules/buttons/image-button-missing-aria"), - RuleTester = require("eslint").RuleTester; +import { Rule } from "eslint"; +import ruleTester from "../helper/ruleTester"; +import rule from "../../../../lib/rules/buttons/image-button-missing-aria"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("image-button-missing-aria", rule, { +ruleTester.run("image-button-missing-aria", rule as unknown as Rule.RuleModule, { valid: [ // give me some code that won't trigger a warning '", diff --git a/tests/lib/rules/checkbox-needs-labelling.js b/tests/lib/rules/checkbox-needs-labelling.test.ts similarity index 86% rename from tests/lib/rules/checkbox-needs-labelling.js rename to tests/lib/rules/checkbox-needs-labelling.test.ts index 1af8ed6..90bb791 100644 --- a/tests/lib/rules/checkbox-needs-labelling.js +++ b/tests/lib/rules/checkbox-needs-labelling.test.ts @@ -1,31 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const RuleTester = require("eslint").RuleTester; - -const rule = require("../../../lib/rules/checkbox-needs-labelling"); - -RuleTester.setDefaultConfig({ - parserOptions: { - ecmaVersion: 6, - ecmaFeatures: { - jsx: true - } - } -}); +import { Rule } from "eslint"; +import ruleTester from "./helper/ruleTester"; +import rule from "../../../lib/rules/checkbox-needs-labelling"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("checkbox-needs-labelling", rule, { +ruleTester.run("checkbox-needs-labelling", rule as unknown as Rule.RuleModule, { valid: [ "<>", `<>`, diff --git a/tests/lib/rules/combobox-needs-labelling.js b/tests/lib/rules/combobox-needs-labelling.test.ts similarity index 87% rename from tests/lib/rules/combobox-needs-labelling.js rename to tests/lib/rules/combobox-needs-labelling.test.ts index 09aa639..cc64590 100644 --- a/tests/lib/rules/combobox-needs-labelling.js +++ b/tests/lib/rules/combobox-needs-labelling.test.ts @@ -1,30 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const rule = require("../../../lib/rules/combobox-needs-labelling"), - RuleTester = require("eslint").RuleTester; - -RuleTester.setDefaultConfig({ - parserOptions: { - ecmaVersion: 6, - ecmaFeatures: { - jsx: true - } - } -}); +import { Rule } from "eslint"; +import ruleTester from "./helper/ruleTester"; +import rule from "../../../lib/rules/combobox-needs-labelling"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("combobox-needs-labelling", rule, { +ruleTester.run("combobox-needs-labelling", rule as unknown as Rule.RuleModule, { valid: [ // give me some code that won't trigger a warning '', diff --git a/tests/lib/rules/dialogbody-needs-title-content-and-actions.js b/tests/lib/rules/dialogbody-needs-title-content-and-actions.test.ts similarity index 78% rename from tests/lib/rules/dialogbody-needs-title-content-and-actions.js rename to tests/lib/rules/dialogbody-needs-title-content-and-actions.test.ts index e430c57..aaf71e3 100644 --- a/tests/lib/rules/dialogbody-needs-title-content-and-actions.js +++ b/tests/lib/rules/dialogbody-needs-title-content-and-actions.test.ts @@ -1,31 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const RuleTester = require("eslint").RuleTester; - -const rule = require("../../../lib/rules/dialogbody-needs-title-content-and-actions"); - -RuleTester.setDefaultConfig({ - parserOptions: { - ecmaVersion: 6, - ecmaFeatures: { - jsx: true - } - } -}); +import { Rule } from "eslint"; +import ruleTester from "./helper/ruleTester"; +import rule from "../../../lib/rules/dialogbody-needs-title-content-and-actions"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("dialogbody-needs-title-content-and-actions", rule, { +ruleTester.run("dialogbody-needs-title-content-and-actions", rule as any as Rule.RuleModule, { valid: [ ` Dialog title @@ -39,8 +27,7 @@ ruleTester.run("dialogbody-needs-title-content-and-actions", rule, { invalid: [ { - code: - ` + code: ` Test @@ -50,8 +37,7 @@ ruleTester.run("dialogbody-needs-title-content-and-actions", rule, { errors: [{ messageId: "dialogBodyOneTitleOneContentOneFooter" }] }, { - code: - ` + code: ` Dialog title @@ -61,12 +47,11 @@ ruleTester.run("dialogbody-needs-title-content-and-actions", rule, { errors: [{ messageId: "dialogBodyOneTitleOneContentOneFooter" }] }, { - code: - ` + code: ` Dialog title Test `, errors: [{ messageId: "dialogBodyOneTitleOneContentOneFooter" }] - }, + } ] }); diff --git a/tests/lib/rules/dialogsurface-needs-aria.js b/tests/lib/rules/dialogsurface-needs-aria.test.ts similarity index 88% rename from tests/lib/rules/dialogsurface-needs-aria.js rename to tests/lib/rules/dialogsurface-needs-aria.test.ts index ea211e4..902e538 100644 --- a/tests/lib/rules/dialogsurface-needs-aria.js +++ b/tests/lib/rules/dialogsurface-needs-aria.test.ts @@ -1,31 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const RuleTester = require("eslint").RuleTester; - -const rule = require("../../../lib/rules/dialogsurface-needs-aria") - -RuleTester.setDefaultConfig({ - parserOptions: { - ecmaVersion: 6, - ecmaFeatures: { - jsx: true - } - } -}); +import { Rule } from "eslint"; +import ruleTester from "./helper/ruleTester"; +import rule from "../../../lib/rules/dialogsurface-needs-aria"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("dialogsurface-needs-aria", rule, { +ruleTester.run("dialogsurface-needs-aria", rule as any as Rule.RuleModule, { valid: [ `<> My Label @@ -71,8 +59,7 @@ ruleTester.run("dialogsurface-needs-aria", rule, { invalid: [ { - code: - `<> + code: `<> Dialog title @@ -87,8 +74,7 @@ ruleTester.run("dialogsurface-needs-aria", rule, { errors: [{ messageId: "missingAriaOnDialogSurface" }] }, { - code: - `<> + code: `<> diff --git a/tests/lib/rules/dropdown-needs-labelling.js b/tests/lib/rules/dropdown-needs-labelling.test.ts similarity index 89% rename from tests/lib/rules/dropdown-needs-labelling.js rename to tests/lib/rules/dropdown-needs-labelling.test.ts index bf76f54..46a9c7e 100644 --- a/tests/lib/rules/dropdown-needs-labelling.js +++ b/tests/lib/rules/dropdown-needs-labelling.test.ts @@ -1,31 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -"use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const RuleTester = require("eslint").RuleTester; - -const rule = require("../../../lib/rules/dropdown-needs-labelling"); - -RuleTester.setDefaultConfig({ - parserOptions: { - ecmaVersion: 6, - ecmaFeatures: { - jsx: true - } - } -}); +import { Rule } from "eslint"; +import ruleTester from "./helper/ruleTester"; +import rule from "../../../lib/rules/dropdown-needs-labelling"; //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester(); -ruleTester.run("dropdown-needs-labelling", rule, { +ruleTester.run("dropdown-needs-labelling", rule as unknown as Rule.RuleModule, { valid: [ `<> {options.map((option) => ( ))}`, `<>