add anchorHasContent rule and tests
MODIFY
packages/@romejs/diagnostics/categories.ts
packages/@romejs/diagnostics/categories.ts
@@ -103,6 +103,7 @@ type LintDiagnosticCategory =
| "lint/getterReturn"
| "lint/importDefaultBasename"
| "lint/jsxA11yAltText"
+ | "lint/jsxA11yAnchorHasContent"
| "lint/jsxA11yHeadingHasContent"
| "lint/jsxA11yHTMLHasLang"
| "lint/jsxA11yIframeHasTitle"

MODIFY
packages/@romejs/diagnostics/descriptions.ts
packages/@romejs/diagnostics/descriptions.ts
@@ -292,6 +292,10 @@ export const descriptions = createMessages({
},
// @romejs/js-compiler
LINT: {
+ JSX_A11Y_ANCHOR_HAS_CONTENT: {
+ category: "lint/jsxA11yAnchorHasContent",
+ message: "Anchor must have content and the content must be accessible by a screen reader.",
+ },
NO_DID_UPDATE_SET_STATE: {
category: "lint/noDidUpdateSetState",
message: "Avoid this.setState in componentDidUpdate",

MODIFY
packages/@romejs/js-compiler/lint/rules/index.ts
packages/@romejs/js-compiler/lint/rules/index.ts
@@ -17,6 +17,7 @@ import emptyMatches from "./regular/emptyMatches";
import getterReturn from "./regular/getterReturn";
import importDefaultBasename from "./regular/importDefaultBasename";
import jsxA11YAltText from "./react/jsxA11yAltText";
+import jsxA11YAnchorHasContent from "./react/jsxA11yAnchorHasContent";
import jsxA11YHeadingHasContent from "./react/jsxA11yHeadingHasContent";
import jsxA11YHTMLHasLang from "./react/jsxA11yHTMLHasLang";
import jsxA11YIframeHasTitle from "./react/jsxA11yIframeHasTitle";
@@ -89,6 +90,7 @@ export const lintTransforms = [
getterReturn,
importDefaultBasename,
jsxA11YAltText,
+ jsxA11YAnchorHasContent,
jsxA11YHeadingHasContent,
jsxA11YHTMLHasLang,
jsxA11YIframeHasTitle,

ADD
packages/@romejs/js-compiler/lint/rules/react/jsxA11yAnchorHasContent.test.ts
+import {test} from "rome";
+import {testLintMultiple} from "../testHelpers";
+
+test(
+ "jsx a11y anchor has content",
+ async (t) => {
+ await testLintMultiple(
+ t,
+ [
+ // INVALID
+ "<a />",
+ "<a><TextWrapper aria-hidden /></a>",
+ // VALID
+ "<a>Anchor Content!</a>",
+ "<a><TextWrapper /></a>",
+ "<a dangerouslySetInnerHTML={{ __html: 'foo' }} />",
+ ],
+ {category: "lint/jsxA11yAnchorHasContent"},
+ );
+ },
+);

ADD
packages/@romejs/js-compiler/lint/rules/react/jsxA11yAnchorHasContent.ts
+import {Path, TransformExitResult} from "@romejs/js-compiler";
+import {JSXElement} from "@romejs/js-ast";
+import {descriptions} from "@romejs/diagnostics";
+import {
+ hasJSXAttribute,
+ isJSXElement
+} from "@romejs/js-ast-utils";
+
+function hasAnchorContent(node: JSXElement): boolean {
+ const dangerouslySetInnerHTML = hasJSXAttribute(node, "dangerouslySetInnerHTML")
+
+ return (
+ (
+ node.children.length > 0 &&
+ !node.children.some(child => child.type === "JSXElement" && hasJSXAttribute(child, "aria-hidden"))
+ )||
+ dangerouslySetInnerHTML
+ );
+}
+
+export default {
+ name: "jsxA11YAnchorHasContent",
+ enter(path: Path): TransformExitResult {
+ const {node} = path;
+ if (isJSXElement(node, "a") && !hasAnchorContent(node)) {
+ path.context.addNodeDiagnostic(
+ node,
+ descriptions.LINT.JSX_A11Y_ANCHOR_HAS_CONTENT,
+ );
+ }
+
+ return node;
+ },
+};

add anchorHasContent rule and tests