feat(rome_js_analyze): noCommentText
MODIFY
crates/rome_js_analyze/src/analyzers.rs
crates/rome_js_analyze/src/analyzers.rs
mod no_async_promise_executor;
pub(crate) use no_async_promise_executor::NoAsyncPromiseExecutor;
+mod no_comment_text;
+pub(crate) use no_comment_text::NoCommentText;
mod no_compare_neg_zero;
pub(crate) use no_compare_neg_zero::NoCompareNegZero;
mod no_dead_code;

ADD
crates/rome_js_analyze/src/analyzers/no_comment_text.rs
+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,
+ })
+ }
+}

MODIFY
crates/rome_js_analyze/src/registry.rs
crates/rome_js_analyze/src/registry.rs
@@ -17,6 +17,9 @@ where
if filter.match_rule::<NoAsyncPromiseExecutor>() {
rules.push::<NoAsyncPromiseExecutor>();
}
+ if filter.match_rule::<NoCommentText>() {
+ rules.push::<NoCommentText>();
+ }
if filter.match_rule::<NoCompareNegZero>() {
rules.push::<NoCompareNegZero>();
}

ADD
crates/rome_js_analyze/tests/specs/noCommentText.tsx
+// 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>;
\ No newline at end of file

MODIFY
website/src/docs/lint/rules/index.md
website/src/docs/lint/rules/index.md
@@ -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>

feat(rome_js_analyze): noCommentText (#2810)