Skip to content

Commit 002cded

Browse files
authored
fix(lint/useExhaustiveDependencies): correctly fix the dependency list from a shorthand object member (#7498)
1 parent bd70f40 commit 002cded

File tree

4 files changed

+114
-7
lines changed

4 files changed

+114
-7
lines changed

.changeset/brave-camels-sin.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
"@biomejs/biome": patch
3+
---
4+
5+
Fixed [#6893](https://github.com/biomejs/biome/issues/6893): The [`useExhaustiveDependencies`](https://biomejs.dev/linter/rules/use-exhaustive-dependencies/) rule now correctly adds a dependency that is captured in a shorthand object member. For example:
6+
7+
```jsx
8+
useEffect(() => {
9+
console.log({firstId, secondId});
10+
}, []);
11+
```
12+
13+
is now correctly fixed to:
14+
15+
```jsx
16+
useEffect(() => {
17+
console.log({firstId, secondId});
18+
}, [firstId, secondId]);
19+
```

crates/biome_js_analyze/src/lint/correctness/use_exhaustive_dependencies.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
use std::collections::BTreeMap;
22

3+
use rustc_hash::{FxHashMap, FxHashSet};
4+
35
use biome_analyze::{FixKind, RuleSource};
46
use biome_analyze::{Rule, RuleDiagnostic, RuleDomain, context::RuleContext, declare_lint_rule};
57
use biome_console::markup;
68
use biome_diagnostics::Severity;
79
use biome_js_factory::make;
810
use biome_js_semantic::{Capture, SemanticModel};
911
use biome_js_syntax::{
10-
AnyJsArrayElement, AnyJsExpression, AnyJsMemberExpression, JsArrayExpression, T, TsTypeofType,
12+
AnyJsArrayElement, AnyJsExpression, AnyJsMemberExpression, JsArrayExpression,
13+
JsReferenceIdentifier, T, TsTypeofType,
1114
};
1215
use biome_js_syntax::{
1316
JsCallExpression, JsSyntaxKind, JsSyntaxNode, JsVariableDeclaration, TextRange,
1417
binding_ext::AnyJsBindingDeclaration,
1518
};
1619
use biome_rowan::{AstNode, AstSeparatedList, BatchMutationExt, SyntaxNodeCast, TriviaPieceKind};
17-
use rustc_hash::{FxHashMap, FxHashSet};
20+
use biome_rule_options::use_exhaustive_dependencies::{
21+
StableHookResult, UseExhaustiveDependenciesOptions,
22+
};
1823

1924
use crate::JsRuleAction;
2025
use crate::react::hooks::*;
2126
use crate::services::semantic::Semantic;
2227

23-
use biome_rule_options::use_exhaustive_dependencies::{
24-
StableHookResult, UseExhaustiveDependenciesOptions,
25-
};
26-
2728
declare_lint_rule! {
2829
/// Enforce all dependencies are correctly specified in a React hook.
2930
///
@@ -1000,7 +1001,11 @@ impl Rule for UseExhaustiveDependencies {
10001001
} => {
10011002
let new_elements = captures.first().into_iter().filter_map(|node| {
10021003
node.ancestors()
1003-
.find_map(|node| node.cast::<AnyJsExpression>()?.trim_trivia())
1004+
.find_map(|node| match JsReferenceIdentifier::cast_ref(&node) {
1005+
Some(node) => Some(make::js_identifier_expression(node).into()),
1006+
_ => node.cast::<AnyJsExpression>(),
1007+
})
1008+
.and_then(|node| node.trim_trivia())
10041009
.map(AnyJsArrayElement::AnyJsExpression)
10051010
});
10061011

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function App() {
2+
const firstId = `${Math.random()}`
3+
const secondId = `${Math.random()}`
4+
5+
React.useEffect(() => {
6+
console.log({firstId, secondId})
7+
}, [])
8+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
---
2+
source: crates/biome_js_analyze/tests/spec_tests.rs
3+
expression: issue6893.js
4+
---
5+
# Input
6+
```js
7+
function App() {
8+
const firstId = `${Math.random()}`
9+
const secondId = `${Math.random()}`
10+
11+
React.useEffect(() => {
12+
console.log({firstId, secondId})
13+
}, [])
14+
}
15+
16+
```
17+
18+
# Diagnostics
19+
```
20+
issue6893.js:5:8 lint/correctness/useExhaustiveDependencies FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
21+
22+
× This hook does not specify its dependency on firstId.
23+
24+
3 │ const secondId = `${Math.random()}`
25+
4 │
26+
> 5 │ React.useEffect(() => {
27+
^^^^^^^^^
28+
6console.log({firstId, secondId})
29+
7}, [])
30+
31+
i This dependency is being used here, but is not specified in the hook dependency list.
32+
33+
5 │ React.useEffect(() => {
34+
> 6console.log({firstId, secondId})
35+
^^^^^^^
36+
7}, [])
37+
8 │ }
38+
39+
i Either include it or remove the dependency array.
40+
41+
i Unsafe fix: Add the missing dependency to the list.
42+
43+
7 │ → },·[firstId])
44+
│ +++++++
45+
46+
```
47+
48+
```
49+
issue6893.js:5:8 lint/correctness/useExhaustiveDependencies FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
50+
51+
× This hook does not specify its dependency on secondId.
52+
53+
3 │ const secondId = `${Math.random()}`
54+
4 │
55+
> 5 │ React.useEffect(() => {
56+
^^^^^^^^^
57+
6console.log({firstId, secondId})
58+
7}, [])
59+
60+
i This dependency is being used here, but is not specified in the hook dependency list.
61+
62+
5 │ React.useEffect(() => {
63+
> 6console.log({firstId, secondId})
64+
^^^^^^^^
65+
7}, [])
66+
8 │ }
67+
68+
i Either include it or remove the dependency array.
69+
70+
i Unsafe fix: Add the missing dependency to the list.
71+
72+
7 │ → },·[secondId])
73+
│ ++++++++
74+
75+
```

0 commit comments

Comments
 (0)