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

feat(rome_js_analyze): noCommentText #2810

Merged
merged 11 commits into from
Jul 6, 2022
2 changes: 2 additions & 0 deletions crates/rome_js_analyze/src/analyzers.rs

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

105 changes: 105 additions & 0 deletions crates/rome_js_analyze/src/analyzers/no_comment_text.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use rome_analyze::{
context::RuleContext, declare_rule, ActionCategory, Ast, Rule, RuleCategory, RuleDiagnostic,
};
use rome_console::markup;
use rome_diagnostics::Applicability;
use rome_js_factory::make;
use rome_js_syntax::{JsxAnyChild, JsxText, TriviaPieceKind, T};
use rome_rowan::{AstNode, AstNodeExt};

use crate::JsRuleAction;
declare_rule! {
/// Prevent comments from being inserted as text nodes
///
/// ## Examples
///
/// ### Invalid
///
/// ```js,expect_diagnostic
/// const a3 = <div>// comment</div>;
/// ```
///
/// ```js,expect_diagnostic
/// const a4 = <div>/* comment */</div>;
/// ```
///
/// ```js,expect_diagnostic
/// const a5 = <div>/** comment */</div>;
/// ```
///
/// ### Valid
///
/// ```js
/// const a = <div>{/* comment */}</div>;
/// const a1 = <div>{/** comment */}</div>;
/// const a2 = <div className={"cls" /* comment */}></div>;
/// ```
pub(crate) NoCommentText = "noCommentText"
}

impl Rule for NoCommentText {
const CATEGORY: RuleCategory = RuleCategory::Lint;

type Query = Ast<JsxText>;
type State = ();
type Signals = Option<Self::State>;

fn run(ctx: &RuleContext<Self>) -> Option<Self::State> {
let n = ctx.query();
let jsx_value = n.text();
let is_single_line_comment = jsx_value.starts_with("//");
let is_multi_line_comment = jsx_value.starts_with("/*") && jsx_value.ends_with("*/");
if is_single_line_comment || is_multi_line_comment {
Some(())
} else {
None
}
}

fn diagnostic(ctx: &RuleContext<Self>, _: &Self::State) -> Option<RuleDiagnostic> {
let node = ctx.query();

Some(RuleDiagnostic::warning(
node.range(),
markup! {
"Wrap "<Emphasis>"comments"</Emphasis>" inside children within "<Emphasis>"braces"</Emphasis>"."
},
))
}

fn action(ctx: &RuleContext<Self>, _: &Self::State) -> Option<JsRuleAction> {
let node = ctx.query();

let normalized_comment = format!(
"/*{}*/",
node.text()
.trim_start_matches("/**")
.trim_start_matches("//")
.trim_start_matches("/*")
.trim_end_matches("*/")
);
let root = ctx.root().replace_node(
JsxAnyChild::JsxText(node.clone()),
JsxAnyChild::JsxExpressionChild(
make::jsx_expression_child(
make::token(T!['{']).with_trailing_trivia(
[(
TriviaPieceKind::MultiLineComment,
normalized_comment.as_str(),
)]
.into_iter(),
),
make::token(T!['}']),
)
.build(),
),
)?;

Some(JsRuleAction {
category: ActionCategory::QuickFix,
applicability: Applicability::MaybeIncorrect,
message: markup! { "Wrap the comments with braces" }.to_owned(),
root,
})
}
}
3 changes: 3 additions & 0 deletions crates/rome_js_analyze/src/registry.rs

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

8 changes: 8 additions & 0 deletions crates/rome_js_analyze/tests/specs/noCommentText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// invalid
const a3 = <div>// comment</div>;
const a4 = <div>/* comment */</div>;
const a5 = <div>/** comment */</div>;
// valid
const a = <div>{/* comment */}</div>;
const a1 = <div>{/** comment */}</div>;
const a2 = <div className={"cls" /* comment */}></div>;
79 changes: 79 additions & 0 deletions crates/rome_js_analyze/tests/specs/noCommentText.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
source: crates/rome_js_analyze/tests/spec_tests.rs
assertion_line: 98
expression: noCommentText.tsx
---
# Input
```js
// invalid
const a3 = <div>// comment</div>;
const a4 = <div>/* comment */</div>;
const a5 = <div>/** comment */</div>;
// valid
const a = <div>{/* comment */}</div>;
const a1 = <div>{/** comment */}</div>;
const a2 = <div className={"cls" /* comment */}></div>;
```

# Diagnostics
```
warning[noCommentText]: Wrap comments inside children within braces.
┌─ noCommentText.tsx:2:17
2 │ const a3 = <div>// comment</div>;
│ ----------

Suggested fix: Wrap the comments with braces
| @@ -1,5 +1,5 @@
0 0 | // invalid
1 | - const a3 = <div>// comment</div>;
1 | + const a3 = <div>{/* comment*/}</div>;
2 2 | const a4 = <div>/* comment */</div>;
3 3 | const a5 = <div>/** comment */</div>;
4 4 | // valid


```

```
warning[noCommentText]: Wrap comments inside children within braces.
┌─ noCommentText.tsx:3:17
3 │ const a4 = <div>/* comment */</div>;
│ -------------

Suggested fix: Wrap the comments with braces
| @@ -1,6 +1,6 @@
0 0 | // invalid
1 1 | const a3 = <div>// comment</div>;
2 | - const a4 = <div>/* comment */</div>;
2 | + const a4 = <div>{/* comment */}</div>;
3 3 | const a5 = <div>/** comment */</div>;
4 4 | // valid
5 5 | const a = <div>{/* comment */}</div>;


```

```
warning[noCommentText]: Wrap comments inside children within braces.
┌─ noCommentText.tsx:4:17
4 │ const a5 = <div>/** comment */</div>;
│ --------------

Suggested fix: Wrap the comments with braces
| @@ -1,7 +1,7 @@
0 0 | // invalid
1 1 | const a3 = <div>// comment</div>;
2 2 | const a4 = <div>/* comment */</div>;
3 | - const a5 = <div>/** comment */</div>;
3 | + const a5 = <div>{/* comment */}</div>;
4 4 | // valid
5 5 | const a = <div>{/* comment */}</div>;
6 6 | const a1 = <div>{/** comment */}</div>;


```


7 changes: 7 additions & 0 deletions website/src/docs/lint/rules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ Disallow the use of <code>arguments</code>
Disallows using an async function as a Promise executor.
</div>
<div class="rule">
<h3 data-toc-exclude id="noCommentText">
<a href="/docs/lint/rules/noCommentText">noCommentText</a>
<a class="header-anchor" href="#noCommentText"></a>
</h3>
Prevent comments from being inserted as text nodes
</div>
<div class="rule">
<h3 data-toc-exclude id="noCompareNegZero">
<a href="/docs/lint/rules/noCompareNegZero">noCompareNegZero</a>
<a class="header-anchor" href="#noCompareNegZero"></a>
Expand Down
72 changes: 72 additions & 0 deletions website/src/docs/lint/rules/noCommentText.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
title: Lint Rule noCommentText
layout: layouts/rule.liquid
---

# noCommentText

Prevent comments from being inserted as text nodes

## Examples

### Invalid

```jsx
const a3 = <div>// comment</div>;
```

{% raw %}<pre class="language-text"><code class="language-text"><span style="color: Orange;">warning</span><span style="color: Orange;">[</span><span style="color: Orange;">noCommentText</span><span style="color: Orange;">]</span><em>: </em><em>Wrap </em><em><em>comments</em></em><em> inside children within </em><em><em>braces</em></em><em>.</em>
<span style="color: rgb(38, 148, 255);">┌</span><span style="color: rgb(38, 148, 255);">─</span> noCommentText.js:1:17
<span style="color: rgb(38, 148, 255);">│</span>
<span style="color: rgb(38, 148, 255);">1</span> <span style="color: rgb(38, 148, 255);">│</span> const a3 = &lt;div&gt;// comment&lt;/div&gt;;
<span style="color: rgb(38, 148, 255);">│</span> <span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span>

<span style="color: rgb(38, 148, 255);">Suggested fix</span><span style="color: rgb(38, 148, 255);">: </span><span style="color: rgb(38, 148, 255);">Wrap the comments with braces</span>
| <span style="color: rgb(38, 148, 255);">@@ -1 +1 @@</span>
0 | <span style="color: Tomato;">- </span><span style="color: Tomato;">const a3 = &lt;div&gt;// comment&lt;/div&gt;;</span>
0 | <span style="color: MediumSeaGreen;">+ </span><span style="color: MediumSeaGreen;">const a3 = &lt;div&gt;{/* comment*/}&lt;/div&gt;;</span>

</code></pre>{% endraw %}

```jsx
const a4 = <div>/* comment */</div>;
```

{% raw %}<pre class="language-text"><code class="language-text"><span style="color: Orange;">warning</span><span style="color: Orange;">[</span><span style="color: Orange;">noCommentText</span><span style="color: Orange;">]</span><em>: </em><em>Wrap </em><em><em>comments</em></em><em> inside children within </em><em><em>braces</em></em><em>.</em>
<span style="color: rgb(38, 148, 255);">┌</span><span style="color: rgb(38, 148, 255);">─</span> noCommentText.js:1:17
<span style="color: rgb(38, 148, 255);">│</span>
<span style="color: rgb(38, 148, 255);">1</span> <span style="color: rgb(38, 148, 255);">│</span> const a4 = &lt;div&gt;/* comment */&lt;/div&gt;;
<span style="color: rgb(38, 148, 255);">│</span> <span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span>

<span style="color: rgb(38, 148, 255);">Suggested fix</span><span style="color: rgb(38, 148, 255);">: </span><span style="color: rgb(38, 148, 255);">Wrap the comments with braces</span>
| <span style="color: rgb(38, 148, 255);">@@ -1 +1 @@</span>
0 | <span style="color: Tomato;">- </span><span style="color: Tomato;">const a4 = &lt;div&gt;/* comment */&lt;/div&gt;;</span>
0 | <span style="color: MediumSeaGreen;">+ </span><span style="color: MediumSeaGreen;">const a4 = &lt;div&gt;{/* comment */}&lt;/div&gt;;</span>

</code></pre>{% endraw %}

```jsx
const a5 = <div>/** comment */</div>;
```

{% raw %}<pre class="language-text"><code class="language-text"><span style="color: Orange;">warning</span><span style="color: Orange;">[</span><span style="color: Orange;">noCommentText</span><span style="color: Orange;">]</span><em>: </em><em>Wrap </em><em><em>comments</em></em><em> inside children within </em><em><em>braces</em></em><em>.</em>
<span style="color: rgb(38, 148, 255);">┌</span><span style="color: rgb(38, 148, 255);">─</span> noCommentText.js:1:17
<span style="color: rgb(38, 148, 255);">│</span>
<span style="color: rgb(38, 148, 255);">1</span> <span style="color: rgb(38, 148, 255);">│</span> const a5 = &lt;div&gt;/** comment */&lt;/div&gt;;
<span style="color: rgb(38, 148, 255);">│</span> <span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span><span style="color: rgb(38, 148, 255);">-</span>

<span style="color: rgb(38, 148, 255);">Suggested fix</span><span style="color: rgb(38, 148, 255);">: </span><span style="color: rgb(38, 148, 255);">Wrap the comments with braces</span>
| <span style="color: rgb(38, 148, 255);">@@ -1 +1 @@</span>
0 | <span style="color: Tomato;">- </span><span style="color: Tomato;">const a5 = &lt;div&gt;/** comment */&lt;/div&gt;;</span>
0 | <span style="color: MediumSeaGreen;">+ </span><span style="color: MediumSeaGreen;">const a5 = &lt;div&gt;{/* comment */}&lt;/div&gt;;</span>

</code></pre>{% endraw %}

### Valid

```jsx
const a = <div>{/* comment */}</div>;
const a1 = <div>{/** comment */}</div>;
const a2 = <div className={"cls" /* comment */}></div>;
```