From ccb2988ee1e60275ec4c42ebd71755f9f2052eb2 Mon Sep 17 00:00:00 2001 From: Ilia Kebets <104737176+ilia-kebets-sonarsource@users.noreply.github.com> Date: Fri, 13 Oct 2023 13:41:25 +0200 Subject: [PATCH] Add rule S6821 (`jsx-a11y/aria-role`): DOM elements with ARIA roles should have a valid non-abstract role (#4268) --- .../jsts/vuetify/typescript-S6821.json | 5 ++ .../javascript/checks/AriaRoleCheck.java | 49 +++++++++++++++++++ .../sonar/javascript/checks/CheckList.java | 1 + .../javascript/rules/javascript/S6821.html | 30 ++++++++++++ .../javascript/rules/javascript/S6821.json | 30 ++++++++++++ .../rules/javascript/Sonar_way_profile.json | 3 +- .../javascript/checks/AriaRoleCheckTest.java | 35 +++++++++++++ 7 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 its/ruling/src/test/expected/jsts/vuetify/typescript-S6821.json create mode 100644 sonar-plugin/javascript-checks/src/main/java/org/sonar/javascript/checks/AriaRoleCheck.java create mode 100644 sonar-plugin/javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/S6821.html create mode 100644 sonar-plugin/javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/S6821.json create mode 100644 sonar-plugin/javascript-checks/src/test/java/org/sonar/javascript/checks/AriaRoleCheckTest.java diff --git a/its/ruling/src/test/expected/jsts/vuetify/typescript-S6821.json b/its/ruling/src/test/expected/jsts/vuetify/typescript-S6821.json new file mode 100644 index 00000000000..140b67ef993 --- /dev/null +++ b/its/ruling/src/test/expected/jsts/vuetify/typescript-S6821.json @@ -0,0 +1,5 @@ +{ +"vuetify:packages/vuetify/src/components/VDivider/VDivider.tsx": [ +65 +] +} diff --git a/sonar-plugin/javascript-checks/src/main/java/org/sonar/javascript/checks/AriaRoleCheck.java b/sonar-plugin/javascript-checks/src/main/java/org/sonar/javascript/checks/AriaRoleCheck.java new file mode 100644 index 00000000000..daf6ed07a94 --- /dev/null +++ b/sonar-plugin/javascript-checks/src/main/java/org/sonar/javascript/checks/AriaRoleCheck.java @@ -0,0 +1,49 @@ +/** + * SonarQube JavaScript Plugin + * Copyright (C) 2011-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.javascript.checks; + +import java.util.Collections; +import java.util.List; +import org.sonar.check.Rule; +import org.sonar.plugins.javascript.api.EslintBasedCheck; +import org.sonar.plugins.javascript.api.JavaScriptRule; +import org.sonar.plugins.javascript.api.TypeScriptRule; + +@TypeScriptRule +@JavaScriptRule +@Rule(key = "S6821") +public class AriaRoleCheck implements EslintBasedCheck { + + @Override + public String eslintKey() { + return "aria-role"; + } + + @Override + public List configurations() { + return Collections.singletonList(new Config()); + } + + private static class Config { + + boolean ignoreNonDOM = true; + String[] allowedInvalidRoles = { "text" }; + } +} diff --git a/sonar-plugin/javascript-checks/src/main/java/org/sonar/javascript/checks/CheckList.java b/sonar-plugin/javascript-checks/src/main/java/org/sonar/javascript/checks/CheckList.java index dc9a0cd7cda..4cb3e0071f3 100644 --- a/sonar-plugin/javascript-checks/src/main/java/org/sonar/javascript/checks/CheckList.java +++ b/sonar-plugin/javascript-checks/src/main/java/org/sonar/javascript/checks/CheckList.java @@ -66,6 +66,7 @@ public static List> getAllChecks() { ArgumentsCallerCalleeUsageCheck.class, ArgumentsUsageCheck.class, AriaProptypesCheck.class, + AriaRoleCheck.class, ArithmeticOperationReturningNanCheck.class, ArrayCallbackWithoutReturnCheck.class, ArrayConstructorsCheck.class, diff --git a/sonar-plugin/javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/S6821.html b/sonar-plugin/javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/S6821.html new file mode 100644 index 00000000000..25c017f54f2 --- /dev/null +++ b/sonar-plugin/javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/S6821.html @@ -0,0 +1,30 @@ +

Why is this an issue?

+

ARIA (Accessible Rich Internet Applications) attributes are used to enhance the accessibility of web content and web applications. These attributes +provide additional information about an element’s role, state, properties, and values to assistive technologies like screen readers.

+

Each role in ARIA has a set of required attributes that must be included for the role to be properly understood by assistive technologies. These +attributes are known as "required aria-* properties".

+

For example, if an element has a role of "checkbox", it must also include the aria-checked property. This property indicates whether the checkbox +is checked (true), unchecked (false), or in a mixed state (mixed).

+

This rules checks that each element with a defined ARIA role also has all required attributes.

+

How to fix it in JSX

+

Check that each element with a defined ARIA role also has all required attributes.

+
+<div role="checkbox">Unchecked</div> {/* Noncompliant: aria-checked is missing */}
+
+

To fix the code add missing aria-* attributes.

+
+<div role="checkbox" aria-checked={isChecked}>Unchecked</div>
+
+

Resources

+

Documentation

+ +

Standards

+ + diff --git a/sonar-plugin/javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/S6821.json b/sonar-plugin/javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/S6821.json new file mode 100644 index 00000000000..9b5d5b90a23 --- /dev/null +++ b/sonar-plugin/javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/S6821.json @@ -0,0 +1,30 @@ +{ + "title": "DOM elements with ARIA roles should have a valid non-abstract role", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "react", + "a11y" + ], + "defaultSeverity": "Major", + "ruleSpecification": "RSPEC-6821", + "sqKey": "S6821", + "scope": "All", + "defaultQualityProfiles": ["Sonar way"], + "quickfix": "infeasible", + "code": { + "impacts": { + "MAINTAINABILITY": "LOW", + "RELIABILITY": "MEDIUM" + }, + "attribute": "LOGICAL" + }, + "compatibleLanguages": [ + "JAVASCRIPT", + "TYPESCRIPT" + ] +} diff --git a/sonar-plugin/javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/Sonar_way_profile.json b/sonar-plugin/javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/Sonar_way_profile.json index 2b4b7815e8e..3d9c5ca6be0 100644 --- a/sonar-plugin/javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/Sonar_way_profile.json +++ b/sonar-plugin/javascript-checks/src/main/resources/org/sonar/l10n/javascript/rules/javascript/Sonar_way_profile.json @@ -293,6 +293,7 @@ "S6775", "S6793", "S6807", - "S6811" + "S6811", + "S6821" ] } diff --git a/sonar-plugin/javascript-checks/src/test/java/org/sonar/javascript/checks/AriaRoleCheckTest.java b/sonar-plugin/javascript-checks/src/test/java/org/sonar/javascript/checks/AriaRoleCheckTest.java new file mode 100644 index 00000000000..15833b73984 --- /dev/null +++ b/sonar-plugin/javascript-checks/src/test/java/org/sonar/javascript/checks/AriaRoleCheckTest.java @@ -0,0 +1,35 @@ +/* + * SonarQube JavaScript Plugin + * Copyright (C) 2011-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.javascript.checks; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.google.gson.Gson; +import org.junit.jupiter.api.Test; + +class AriaRoleCheckTest { + + @Test + void config() { + String configAsString = new Gson().toJson(new AriaRoleCheck().configurations()); + assertThat(configAsString) + .isEqualTo("[{\"ignoreNonDOM\":true,\"allowedInvalidRoles\":[\"text\"]}]"); + } +}