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

Commit 9360776

Browse files
authored
fix(rome_js_analyze): fix a false positive for noDuplicateCase (#4709)
1 parent 4c8cf32 commit 9360776

File tree

7 files changed

+50
-27
lines changed

7 files changed

+50
-27
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ if no error diagnostics are emitted.
174174

175175
- Fix [`noInvalidConstructorSuper`](https://docs.rome.tools/lint/rules/noinvalidconstructorsuper/) rule that erroneously reported generic parents [#4624](https://github.com/rome/tools/issues/4624).
176176

177+
- Fix [`noDuplicateCase`](https://docs.rome.tools/lint/rules/noDuplicateCase/) rule that erroneously reported as equals the strings literals `"'"` and `'"'` [#4706](https://github.com/rome/tools/issues/4706).
178+
177179
- Relax [`noBannedTypes`](https://docs.rome.tools/lint/rules/nobannedtypes/) and improve documentation
178180

179181
The rule no longer reports a user type that reuses a banned type name.

crates/rome_js_analyze/src/analyzers/style/use_enum_initializers.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use rome_analyze::{declare_rule, ActionCategory, Ast, Rule, RuleDiagnostic};
44
use rome_console::markup;
55
use rome_diagnostics::Applicability;
66
use rome_js_factory::make;
7-
use rome_js_syntax::{AnyJsExpression, AnyJsLiteralExpression, JsSyntaxKind, TsEnumMember};
7+
use rome_js_syntax::{
8+
inner_text, AnyJsExpression, AnyJsLiteralExpression, JsSyntaxKind, TsEnumMember,
9+
};
810
use rome_rowan::{AstNode, BatchMutationExt, Direction};
911

1012
declare_rule! {
@@ -118,8 +120,7 @@ impl Rule for UseEnumInitializers {
118120
}
119121
AnyJsLiteralExpression::JsStringLiteralExpression(expr) => {
120122
let prev_enum_delim_val = expr.value_token().ok()?;
121-
let prev_enum_delim_val = prev_enum_delim_val.text();
122-
let prev_enum_val = &prev_enum_delim_val[1..(prev_enum_delim_val.len() - 1)];
123+
let prev_enum_val = inner_text(&prev_enum_delim_val);
123124
if prev_name.text() == prev_enum_val {
124125
let enum_name = enum_member.name().ok()?.text();
125126
Some(AnyJsLiteralExpression::JsStringLiteralExpression(

crates/rome_js_analyze/src/semantic_analyzers/nursery/use_naming_convention.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rome_deserialize::{
1717
use rome_diagnostics::Applicability;
1818
use rome_js_semantic::CanBeImportedExported;
1919
use rome_js_syntax::{
20-
binding_ext::AnyJsBindingDeclaration, AnyJsClassMember, AnyJsObjectMember,
20+
binding_ext::AnyJsBindingDeclaration, inner_text, AnyJsClassMember, AnyJsObjectMember,
2121
AnyJsVariableDeclaration, AnyTsTypeMember, JsIdentifierBinding, JsLiteralExportName,
2222
JsLiteralMemberName, JsPrivateClassMemberName, JsSyntaxKind, JsSyntaxToken,
2323
JsVariableDeclarator, JsVariableKind, TsEnumMember, TsIdentifierBinding, TsTypeParameterName,
@@ -290,10 +290,7 @@ impl Rule for UseNamingConvention {
290290
return None;
291291
}
292292
let name_token = node.name_token().ok()?;
293-
let mut name = name_token.text_trimmed();
294-
if name_token.kind() == JsSyntaxKind::JS_STRING_LITERAL {
295-
name = &name[1..name.len() - 1];
296-
}
293+
let name = inner_text(&name_token);
297294
if !is_js_ident(name) {
298295
// ignore non-identifier strings
299296
return None;
@@ -323,10 +320,7 @@ impl Rule for UseNamingConvention {
323320
suggested_name,
324321
} = state;
325322
let name_token = ctx.query().name_token().ok()?;
326-
let mut name = name_token.text_trimmed();
327-
if name_token.kind() == JsSyntaxKind::JS_STRING_LITERAL {
328-
name = &name[1..name.len() - 1];
329-
}
323+
let name = inner_text(&name_token);
330324
let trimmed_name = trim_underscore_dollar(name);
331325
let allowed_cases = element.allowed_cases(ctx.options());
332326
let allowed_case_names = allowed_cases

crates/rome_js_analyze/src/utils.rs

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rome_js_factory::make;
22
use rome_js_syntax::{
3-
AnyJsStatement, JsLanguage, JsModuleItemList, JsStatementList, JsSyntaxNode, JsSyntaxToken,
3+
inner_text, AnyJsStatement, JsLanguage, JsModuleItemList, JsStatementList, JsSyntaxNode,
44
JsVariableDeclaration, JsVariableDeclarator, JsVariableDeclaratorList, JsVariableStatement, T,
55
};
66
use rome_rowan::{AstNode, AstSeparatedList, BatchMutation, Direction, WalkEvent};
@@ -225,7 +225,7 @@ pub(crate) fn is_node_equal(a_node: &JsSyntaxNode, b_node: &JsSyntaxNode) -> boo
225225
(None, Some(_)) | (Some(_), None) => return false,
226226
// both are tokens
227227
(Some(a), Some(b)) => {
228-
if !is_token_text_equal(a, b) {
228+
if inner_text(a) != inner_text(b) {
229229
return false;
230230
}
231231
continue;
@@ -236,18 +236,6 @@ pub(crate) fn is_node_equal(a_node: &JsSyntaxNode, b_node: &JsSyntaxNode) -> boo
236236
true
237237
}
238238

239-
/// Verify that tokens' inner text are equal
240-
fn is_token_text_equal(a: &JsSyntaxToken, b: &JsSyntaxToken) -> bool {
241-
static QUOTES: [char; 2] = ['"', '\''];
242-
243-
a.token_text_trimmed()
244-
.trim_start_matches(QUOTES)
245-
.trim_end_matches(QUOTES)
246-
== b.token_text_trimmed()
247-
.trim_start_matches(QUOTES)
248-
.trim_end_matches(QUOTES)
249-
}
250-
251239
#[test]
252240
fn ok_to_camel_case() {
253241
assert_eq!(to_camel_case("camelCase"), Cow::Borrowed("camelCase"));

crates/rome_js_analyze/tests/specs/suspicious/noDuplicateCase/valid.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,9 @@ switch (a) {
113113
case toString:
114114
break;
115115
}
116+
switch (a) {
117+
case "'":
118+
return ''';
119+
case '"':
120+
return '"';
121+
}

crates/rome_js_analyze/tests/specs/suspicious/noDuplicateCase/valid.js.snap

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,12 @@ switch (a) {
119119
case toString:
120120
break;
121121
}
122-
122+
switch (a) {
123+
case "'":
124+
return ''';
125+
case '"':
126+
return '"';
127+
}
123128
```
124129

125130

crates/rome_js_syntax/src/lib.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,3 +272,30 @@ impl OperatorPrecedence {
272272
matches!(self, OperatorPrecedence::Exponential)
273273
}
274274
}
275+
276+
/// Similar to `JsSyntaxToken::text_trimmed` with the difference that delimiters of string literals are trimmed.
277+
///
278+
/// ## Examples
279+
///
280+
/// ```
281+
/// use rome_js_syntax::{JsSyntaxKind, JsSyntaxToken, inner_text};
282+
///
283+
/// let a = JsSyntaxToken::new_detached(JsSyntaxKind::JS_STRING_LITERAL, "'inner_text'", [], []);
284+
/// let b = JsSyntaxToken::new_detached(JsSyntaxKind::JS_STRING_LITERAL, "\"inner_text\"", [], []);
285+
/// assert_eq!(inner_text(&a), inner_text(&b));
286+
///
287+
/// let a = JsSyntaxToken::new_detached(JsSyntaxKind::LET_KW, "let", [], []);
288+
/// let b = JsSyntaxToken::new_detached(JsSyntaxKind::LET_KW, "let", [], []);
289+
/// assert_eq!(inner_text(&a), inner_text(&b));
290+
///
291+
/// let a = JsSyntaxToken::new_detached(JsSyntaxKind::LET_KW, "let", [], []);
292+
/// let b = JsSyntaxToken::new_detached(JsSyntaxKind::CONST_KW, "const", [], []);
293+
/// assert!(inner_text(&a) != inner_text(&b));
294+
/// ```
295+
pub fn inner_text(token: &JsSyntaxToken) -> &str {
296+
let mut result = token.text_trimmed();
297+
if token.kind() == JsSyntaxKind::JS_STRING_LITERAL {
298+
result = &result[1..result.len() - 1];
299+
}
300+
result
301+
}

0 commit comments

Comments
 (0)