feat: jsx/noImplicitBoolean lint rule
MODIFY
packages/@romefrontend/compiler/lint/rules/index.ts
packages/@romefrontend/compiler/lint/rules/index.ts
@@ -84,6 +84,7 @@ import tabindexNoPositive from "./jsx-a11y/tabindexNoPositive";
import fileExtension from "./jsx/fileExtension";
import noCommentText from "./jsx/noCommentText";
import noDuplicateProps from "./jsx/noDuplicateProps";
+import noImplicitBoolean from "./jsx/noImplicitBoolean";
import pascalCase from "./jsx/pascalCase";
import propsNoSpreading from "./jsx/propsNoSpreading";
import buttonHasType from "./react/buttonHasType";
@@ -191,6 +192,7 @@ export const lintTransforms = [
fileExtension,
noCommentText,
noDuplicateProps,
+ noImplicitBoolean,
pascalCase,
propsNoSpreading,
buttonHasType,

MODIFY
packages/@romefrontend/compiler/lint/rules/jsx-a11y/altText.test.md
packages/@romefrontend/compiler/lint/rules/jsx-a11y/altText.test.md
### `11: formatted`
```
-<img {...props} alt />;
+<img {...props} alt={true} />;
```
### `17: formatted`
```
-<object aria-label />;
+<object aria-label={true} />;
```
### `23: formatted`
```
-<area {...props} alt />;
+<area {...props} alt={true} />;
```
### `27: formatted`
```
-<input type="image" {...props} alt />;
+<input type="image" {...props} alt={true} />;
```

MODIFY
packages/@romefrontend/compiler/lint/rules/jsx-a11y/anchorHasContent.test.md
packages/@romefrontend/compiler/lint/rules/jsx-a11y/anchorHasContent.test.md
```
<a>
- <TextWrapper aria-hidden />
+ <TextWrapper aria-hidden={true} />
</a>;
```
```
<a>
- <TextWrapper aria-hidden />
+ <TextWrapper aria-hidden={true} />
visible content
</a>;

MODIFY
packages/@romefrontend/compiler/lint/rules/jsx-a11y/anchorHasContent.test.ts
packages/@romefrontend/compiler/lint/rules/jsx-a11y/anchorHasContent.test.ts
@@ -12,7 +12,7 @@ test(
"<a>Anchor Content!</a>",
"<a><TextWrapper /></a>",
"<a dangerouslySetInnerHTML={{ __html: 'foo' }} />",
- "<a><TextWrapper aria-hidden /> visible content</a>",
+ "<a><TextWrapper aria-hidden={true} /> visible content</a>",
],
},
{category: "lint/jsx-a11y/anchorHasContent"},

MODIFY
packages/@romefrontend/compiler/lint/rules/jsx-a11y/ariaUnsupportedElements.test.md
packages/@romefrontend/compiler/lint/rules/jsx-a11y/ariaUnsupportedElements.test.md
### `6: formatted`
```
-<style aria-labelledby>
+<style aria-labelledby={true}>
</style>;
```
### `11: formatted`
```
-<style parole>
+<style parole={true}>
</style>;
```

MODIFY
packages/@romefrontend/compiler/lint/rules/jsx-a11y/headingHasContent.test.md
packages/@romefrontend/compiler/lint/rules/jsx-a11y/headingHasContent.test.md
```
<h1>
- <TextWrapper aria-hidden />
+ <TextWrapper aria-hidden={true} />
</h1>;
```
```
<h1>
- <div aria-hidden />
+ <div aria-hidden={true} />
</h1>;
```
```
<h1>
- <div aria-hidden />
+ <div aria-hidden={true} />
visible content
</h1>;

MODIFY
packages/@romefrontend/compiler/lint/rules/jsx-a11y/mediaHasCaption.test.md
packages/@romefrontend/compiler/lint/rules/jsx-a11y/mediaHasCaption.test.md
### `6: formatted`
```
-<video muted {...props}>
+<video muted={true} {...props}>
</video>;
```

ADD
packages/@romefrontend/compiler/lint/rules/jsx/noImplicitBoolean.test.ts
+import {test} from "rome";
+import {testLint} from "../../utils/testing";
+
+test(
+ "jsx no implicit boolean",
+ async (t) => {
+ await testLint(
+ t,
+ {
+ invalid: ["<input disabled />"],
+ valid: [
+ "<input disabled={false} />",
+ "<input disabled={''} />",
+ "<input disabled={0} />",
+ "<input disabled={undefined} />",
+ '<input disabled="false" />',
+ ],
+ },
+ {category: "lint/jsx/noImplicitBoolean"},
+ );
+ },
+);

ADD
packages/@romefrontend/compiler/lint/rules/jsx/noImplicitBoolean.ts
+import {Path, TransformExitResult} from "@romefrontend/compiler";
+import {descriptions} from "@romefrontend/diagnostics";
+import {jsBooleanLiteral, jsxExpressionContainer} from "@romefrontend/ast";
+
+export default {
+ name: "jsxNoImplicitBoolean",
+ enter(path: Path): TransformExitResult {
+ const {context, node} = path;
+
+ if (node.type === "JSXAttribute" && !node.value) {
+ return context.addFixableDiagnostic(
+ {
+ old: node,
+ fixed: {
+ ...node,
+ value: jsxExpressionContainer.create({
+ expression: jsBooleanLiteral.quick(true),
+ }),
+ },
+ },
+ descriptions.LINT.JSX_NO_IMPLICIT_BOOLEAN,
+ );
+ }
+
+ return node;
+ },
+};

MODIFY
packages/@romefrontend/diagnostics/categories.ts
packages/@romefrontend/diagnostics/categories.ts
@@ -176,6 +176,7 @@ type LintDiagnosticCategory =
| "lint/jsx/fileExtension"
| "lint/jsx/noCommentText"
| "lint/jsx/noDuplicateProps"
+ | "lint/jsx/noImplicitBoolean"
| "lint/jsx/pascalCase"
| "lint/jsx/propsNoSpreading"
| "lint/react/buttonHasType"

MODIFY
packages/@romefrontend/diagnostics/descriptions/lint.ts
packages/@romefrontend/diagnostics/descriptions/lint.ts
@@ -16,6 +16,10 @@ import {buildSuggestionAdvice} from "../helpers";
import {createDiagnosticsCategory, orJoin} from "./index";
export const lint = createDiagnosticsCategory({
+ JSX_NO_IMPLICIT_BOOLEAN: {
+ category: "lint/jsx/noImplicitBoolean",
+ message: "Use explicit boolean values for boolean JSX props.",
+ },
JS_NO_NESTED_TERNARY: {
category: "lint/js/noNestedTernary",
message: "Nesting ternary expressions can make code more difficult to understand.",

MODIFY
website/src/docs/lint/rules/index.md
website/src/docs/lint/rules/index.md
@@ -99,6 +99,7 @@ showHero: false
| file-extension | |
| no-comment-text | |
| no-duplicate-props | |
+| [no-implicit-boolean](/docs/lint/rules/jsx/no-implicit-boolean) | MISSING DOCUMENTATION |
| pascal-case | |
| props-no-spreading | |

ADD
website/src/docs/lint/rules/jsx/no-implicit-boolean.md
+---
+title: Rome
+layout: layouts/base.njk
+showHero: false
+description: MISSING DOCUMENTATION
+---
+
+# noImplicitBoolean
+
+not documented yet

feat: jsx/noImplicitBoolean lint rule (#779)