Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

feat(rome_analyze): noImplicitBoolean #2702

Merged
merged 11 commits into from
Jun 14, 2022
2 changes: 2 additions & 0 deletions crates/rome_analyze/src/analyzers.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

88 changes: 88 additions & 0 deletions crates/rome_analyze/src/analyzers/no_implicit_boolean.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use rome_console::markup;
use rome_diagnostics::Applicability;
use rome_js_factory::make;
use rome_js_syntax::{
JsAnyLiteralExpression, JsAnyRoot, JsSyntaxKind, JsxAnyAttributeValue, JsxAttribute,
JsxAttributeFields, T,
};
use rome_rowan::{AstNode, AstNodeExt};

use crate::registry::{JsRuleAction, Rule, RuleDiagnostic};
use crate::{ActionCategory, RuleCategory};

pub(crate) enum NoImplicitBoolean {}

impl Rule for NoImplicitBoolean {
const NAME: &'static str = "noImplicitBoolean";
const CATEGORY: RuleCategory = RuleCategory::Lint;

type Query = JsxAttribute;
type State = ();

fn run(n: &Self::Query) -> Option<Self::State> {
match n.initializer() {
Some(_) => None,
None => Some(()),
}
}

fn diagnostic(n: &Self::Query, _: &Self::State) -> Option<RuleDiagnostic> {
Some(RuleDiagnostic::warning(
n.range(),
markup! {
"Use explicit boolean values for boolean JSX props."
}
.to_owned(),
))
}

fn action(root: JsAnyRoot, n: &Self::Query, _: &Self::State) -> Option<JsRuleAction> {
let JsxAttributeFields {
name,
initializer: _,
} = n.as_fields();

let name = name.ok()?;
// we use this variable for constructing `JsxAnyAttributeName` without clone the name, so we pre compute the type here.

let name_syntax = name.syntax();

// we need to move trailing_trivia of name_syntax to close_curly_token
// <div disabled /**test*/ /> -> <div disabled={true}/**test*/ />
let last_token_of_name_syntax = name_syntax.last_token()?;
// drop the trailing trivia of name_syntax, at CST level it means
// clean the trailing trivia of last token of name_syntax
let next_last_token_of_name_syntax = last_token_of_name_syntax
.clone()
.with_trailing_trivia(std::iter::empty());

let next_name = name.replace_token_discard_trivia(
last_token_of_name_syntax,
next_last_token_of_name_syntax,
)?;
let attr_value = make::jsx_expression_attribute_value(
make::token(JsSyntaxKind::L_CURLY),
rome_js_syntax::JsAnyExpression::JsAnyLiteralExpression(
JsAnyLiteralExpression::JsBooleanLiteralExpression(
make::js_boolean_literal_expression(make::token(T![true])),
),
),
make::token(JsSyntaxKind::R_CURLY),
);
let next_attr = make::jsx_attribute(next_name).with_initializer(
make::jsx_attribute_initializer_clause(
make::token(T![=]),
JsxAnyAttributeValue::JsxExpressionAttributeValue(attr_value),
),
);
let next_attr = next_attr.build();

let root = root.replace_node(n.clone(), next_attr)?;
Some(JsRuleAction {
category: ActionCategory::QuickFix,
applicability: Applicability::Always,
message: markup! { "Add explicit `true` literal for this attribute" }.to_owned(),
root,
})
}
}
1 change: 1 addition & 0 deletions crates/rome_analyze/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ impl_registry_builders!(
NoCompareNegZero,
NoDelete,
NoDoubleEquals,
NoImplicitBoolean,
NoNegationElse,
UseSingleCaseStatement,
UseSingleVarDeclarator,
Expand Down
2 changes: 1 addition & 1 deletion crates/rome_analyze/tests/spec_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rome_diagnostics::{file::SimpleFile, termcolor::NoColor, Diagnostic};
use rome_js_parser::parse;
use rome_rowan::{AstNode, Language};

tests_macros::gen_tests! {"tests/specs/**/*.js", crate::run_test, "module"}
tests_macros::gen_tests! {"tests/specs/**/*.{js,jsx}", crate::run_test, "module"}

fn run_test(input: &'static str, _: &str, _: &str, _: &str) {
register_leak_checker();
Expand Down
11 changes: 11 additions & 0 deletions crates/rome_analyze/tests/specs/noImplicitBoolean.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//valid
<input disabled={false} />;
<input disabled={""} />;
<input disabled={0} />;
<input disabled={undefined} />;
<input disabled="false" />;

//invalid
<input disabled />;
<input accept/** some comment */ />;
<input /** some comment */ accept />;
80 changes: 80 additions & 0 deletions crates/rome_analyze/tests/specs/noImplicitBoolean.jsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
source: crates/rome_analyze/tests/spec_tests.rs
assertion_line: 98
expression: noImplicitBoolean.jsx
---
# Input
```js
//valid
<input disabled={false} />;
<input disabled={""} />;
<input disabled={0} />;
<input disabled={undefined} />;
<input disabled="false" />;

//invalid
<input disabled />;
<input accept/** some comment */ />;
<input /** some comment */ accept />;

```

# Diagnostics
```
warning[noImplicitBoolean]: Use explicit boolean values for boolean JSX props.
┌─ noImplicitBoolean.jsx:9:8
9 │ <input disabled />;
│ --------

Safe fix: Add explicit `true` literal for this attribute
| @@ -6,6 +6,6 @@
5 5 | <input disabled="false" />;
6 6 |
7 7 | //invalid
8 | - <input disabled />;
8 | + <input disabled={true} />;
9 9 | <input accept/** some comment */ />;
10 10 | <input /** some comment */ accept />;


```

```
warning[noImplicitBoolean]: Use explicit boolean values for boolean JSX props.
┌─ noImplicitBoolean.jsx:10:8
10 │ <input accept/** some comment */ />;
│ ------

Safe fix: Add explicit `true` literal for this attribute
| @@ -7,5 +7,5 @@
6 6 |
7 7 | //invalid
8 8 | <input disabled />;
9 | - <input accept/** some comment */ />;
9 | + <input accept={true}/** some comment */ />;
10 10 | <input /** some comment */ accept />;


```

```
warning[noImplicitBoolean]: Use explicit boolean values for boolean JSX props.
┌─ noImplicitBoolean.jsx:11:28
11 │ <input /** some comment */ accept />;
│ ------

Safe fix: Add explicit `true` literal for this attribute
| @@ -8,4 +8,4 @@
7 7 | //invalid
8 8 | <input disabled />;
9 9 | <input accept/** some comment */ />;
10 | - <input /** some comment */ accept />;
10 | + <input /** some comment */ accept={true} />;


```