Skip to content

Commit

Permalink
feat(lint): implement duplicate dependency error (#2991)
Browse files Browse the repository at this point in the history
  • Loading branch information
tunamaguro authored May 30, 2024
1 parent 13811df commit 9e4feb6
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b

Contributed by @lutaok

- Make [useExhaustiveDependencies](https://biomejs.dev/linter/rules/use-exhaustive-dependencies/) report duplicate dependencies. Contributed by @tunamaguro

#### Bug fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,23 @@ impl Rule for UseExhaustiveDependencies {
})
});

// Find duplicated deps from specified ones
{
let mut dep_list: BTreeMap<String, AnyJsExpression> = BTreeMap::new();
for dep in correct_deps.iter() {
let expression_name = dep.to_string();
if dep_list.contains_key(&expression_name) {
signals.push(Fix::RemoveDependency {
function_name_range: result.function_name_range,
component_function: component_function.clone(),
dependencies: vec![dep.clone()],
});
continue;
}
dep_list.insert(expression_name, dep.clone());
}
}

// Find correctly specified dependencies with an unstable identity,
// since they would trigger re-evaluation on every render.
let unstable_deps = correct_deps.into_iter().filter_map(|dep| {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useCallback } from "react";

function Component1({ a }) {
const handle = useCallback(() => {
console.log(a);
}, [a, a]);
}

function Component2() {
const [local,SetLocal] = useState(0);
const handle = useCallback(() => {
console.log(local);
}, [local, local]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
source: crates/biome_js_analyze/tests/spec_tests.rs
expression: duplicateDependencies.js
---
# Input
```jsx
import { useCallback } from "react";

function Component1({ a }) {
const handle = useCallback(() => {
console.log(a);
}, [a, a]);
}

function Component2() {
const [local,SetLocal] = useState(0);
const handle = useCallback(() => {
console.log(local);
}, [local, local]);
}
```

# Diagnostics
```
duplicateDependencies.js:4:20 lint/correctness/useExhaustiveDependencies ━━━━━━━━━━━━━━━━━━━━━━━━━━━
! This hook specifies more dependencies than necessary: a
3 │ function Component1({ a }) {
> 4 │ const handle = useCallback(() => {
│ ^^^^^^^^^^^
5 │ console.log(a);
6 │ }, [a, a]);
i Outer scope values aren't valid dependencies because mutating them doesn't re-render the component.
4 │ const handle = useCallback(() => {
5 │ console.log(a);
> 6 │ }, [a, a]);
│ ^
7 │ }
8 │
```

```
duplicateDependencies.js:11:20 lint/correctness/useExhaustiveDependencies ━━━━━━━━━━━━━━━━━━━━━━━━━━
! This hook specifies more dependencies than necessary: local
9 │ function Component2() {
10 │ const [local,SetLocal] = useState(0);
> 11 │ const handle = useCallback(() => {
│ ^^^^^^^^^^^
12 │ console.log(local);
13 │ }, [local, local]);
i This dependency can be removed from the list.
11 │ const handle = useCallback(() => {
12 │ console.log(local);
> 13 │ }, [local, local]);
│ ^^^^^
14 │ }
```

0 comments on commit 9e4feb6

Please sign in to comment.