Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .changeset/seven-bats-write.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
"@biomejs/biome": patch
---

Added the new nursery rule [`noDuplicateDependencies`](https://next.biomejs.dev/linter/rules/no-duplicate-dependencies/), which verifies that no dependencies are duplicated between the `bundledDependencies`, `bundleDependencies`, `dependencies`, `devDependencies`, `overrides`, `optionalDependencies`, and `peerDependencies` sections.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Clarify scope: intra-group duplicates are also reported.

The rule (and tests) also flag duplicates within the same section (e.g. "dependencies" twice). The sentence currently implies only cross-section checks.

Apply this wording tweak:

-Added the new nursery rule [`noDuplicateDependencies`](https://next.biomejs.dev/linter/rules/no-duplicate-dependencies/), which verifies that no dependencies are duplicated between the `bundledDependencies`, `bundleDependencies`, `dependencies`, `devDependencies`, `overrides`, `optionalDependencies`, and `peerDependencies` sections.
+Added the new nursery rule [`noDuplicateDependencies`](https://next.biomejs.dev/linter/rules/no-duplicate-dependencies/), which reports duplicate dependencies within a section and across the following sections: `bundledDependencies`, `bundleDependencies`, `dependencies`, `devDependencies`, `overrides`, `optionalDependencies`, and `peerDependencies`.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Added the new nursery rule [`noDuplicateDependencies`](https://next.biomejs.dev/linter/rules/no-duplicate-dependencies/), which verifies that no dependencies are duplicated between the `bundledDependencies`, `bundleDependencies`, `dependencies`, `devDependencies`, `overrides`, `optionalDependencies`, and `peerDependencies` sections.
Added the new nursery rule [`noDuplicateDependencies`](https://next.biomejs.dev/linter/rules/no-duplicate-dependencies/), which reports duplicate dependencies within a section and across the following sections: `bundledDependencies`, `bundleDependencies`, `dependencies`, `devDependencies`, `overrides`, `optionalDependencies`, and `peerDependencies`.
🤖 Prompt for AI Agents
In .changeset/seven-bats-write.md around line 5, the release note implies the
rule only checks duplicates across different dependency sections; update the
wording to clarify that the rule also reports duplicate entries within the same
section (intra-group duplicates). Edit the sentence to explicitly state it flags
duplicates both between sections and within a single section (e.g., the same
dependency listed twice in "dependencies"), keeping the rest of the description
and the link intact.

💡 Verification agent

🧩 Analysis chain

Quick sanity checks: rule version and test coverage.

Two verifications to keep us honest:

  • The rule’s declare_lint_rule! should set version: "next".
  • Tests should include bundledDependencies, bundleDependencies, and overrides.

Run this from the repo root.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Checking rule version marker..."
if rg -n 'version:\s*"next"' crates/biome_json_analyze/src/lint/nursery/no_duplicate_dependencies.rs >/dev/null; then
  echo "OK: version \"next\" found."
else
  echo "MISSING: version \"next\" not found in declare_lint_rule!" >&2
  exit 1
fi

echo
echo "Checking tests mention bundled/bundle/overrides..."
RG_PATH='crates/biome_json_analyze/tests/specs/nursery/noDuplicateDependencies'
rg -n --hidden 'bundledDependencies|bundleDependencies|overrides' "$RG_PATH" -H -A 1 -B 1 || {
  echo "No occurrences found in $RG_PATH. Consider adding at least one fixture/snapshot for each key." >&2
  exit 2
}

echo "All checks passed."

Length of output: 1981


Add missing test fixtures for bundledDependencies and overrides

Good news: version: "next" is correctly set in no_duplicate_dependencies.rs. However, the existing tests only cover bundleDependencies. Please add fixtures/snapshots under:

  • crates/biome_json_analyze/tests/specs/nursery/noDuplicateDependencies/invalid/bundledDependencies/...
  • crates/biome_json_analyze/tests/specs/nursery/noDuplicateDependencies/invalid/overrides/...

so that bundledDependencies and overrides are each exercised by the rule.


For example, the following snippets will trigger the rule:

```json
{
"dependencies": {
"foo": ""
},
"devDependencies": {
"foo": ""
}
}
```

```json
{
"dependencies": {
"foo": ""
},
"optionalDependencies": {
"foo": ""
}
}
```

```json
{
"dependencies": {
"foo": ""
},
"peerDependencies": {
"foo": ""
}
}
```
18 changes: 17 additions & 1 deletion crates/biome_analyze/src/rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ pub enum RuleSource {
EslintVitest(&'static str),
/// Rules from [Eslint Plugin Vue.js](https://eslint.vuejs.org/)
EslintVueJs(&'static str),
/// Rules from [Eslint Plugin Package.json](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json)
EslintPackageJson(&'static str),
/// Rules from [Eslint Plugin Package.json Dependencies](https://github.com/idan-at/eslint-plugin-package-json-dependencies)
EslintPackageJsonDependencies(&'static str),
}

impl PartialEq for RuleSource {
Expand Down Expand Up @@ -202,6 +206,10 @@ impl std::fmt::Display for RuleSource {
Self::DenoLint(_) => write!(f, "deno-lint"),
Self::EslintVitest(_) => write!(f, "@vitest/eslint-plugin"),
Self::EslintVueJs(_) => write!(f, "eslint-plugin-vue"),
Self::EslintPackageJson(_) => write!(f, "eslint-plugin-package-json"),
Self::EslintPackageJsonDependencies(_) => {
write!(f, "eslint-plugin-package-json-dependencies")
}
}
}
}
Expand Down Expand Up @@ -278,7 +286,9 @@ impl RuleSource {
| Self::Stylelint(rule_name)
| Self::DenoLint(rule_name)
| Self::EslintVitest(rule_name)
| Self::EslintVueJs(rule_name) => rule_name,
| Self::EslintVueJs(rule_name)
| Self::EslintPackageJson(rule_name)
| Self::EslintPackageJsonDependencies(rule_name) => rule_name,
}
}

Expand Down Expand Up @@ -317,6 +327,10 @@ impl RuleSource {
Self::DenoLint(rule_name) => format!("deno-lint/{rule_name}"),
Self::EslintVitest(rule_name) => format!("vitest/{rule_name}"),
Self::EslintVueJs(rule_name) => format!("vue/{rule_name}"),
Self::EslintPackageJson(rule_name) => format!("package-json/{rule_name}"),
Self::EslintPackageJsonDependencies(rule_name) => {
format!("package-json-dependencies/{rule_name}")
}
}
}

Expand Down Expand Up @@ -354,6 +368,8 @@ impl RuleSource {
Self::DenoLint(rule_name) => format!("https://lint.deno.land/rules/{rule_name}"),
Self::EslintVitest(rule_name) => format!("https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/{rule_name}.md"),
Self::EslintVueJs(rule_name) => format!("https://eslint.vuejs.org/rules/{rule_name}"),
Self::EslintPackageJson(rule_name) => format!("https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/blob/main/docs/rules/{rule_name}.md"),
Self::EslintPackageJsonDependencies(rule_name) => format!("https://github.com/idan-at/eslint-plugin-package-json-dependencies/blob/master/docs/rules/{rule_name}.md"),
}
}

Expand Down
24 changes: 24 additions & 0 deletions crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs

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

129 changes: 75 additions & 54 deletions crates/biome_configuration/src/analyzer/linter/rules.rs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions crates/biome_diagnostics_categories/src/categories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ define_categories! {
"lint/suspicious/noDuplicateCase": "https://biomejs.dev/linter/rules/no-duplicate-case",
"lint/suspicious/noDuplicateClassMembers": "https://biomejs.dev/linter/rules/no-duplicate-class-members",
"lint/suspicious/noDuplicateCustomProperties": "https://biomejs.dev/linter/rules/no-duplicate-custom-properties",
"lint/nursery/noDuplicateDependencies": "https://biomejs.dev/linter/rules/no-duplicate-dependencies",
"lint/suspicious/noDuplicateElseIf": "https://biomejs.dev/linter/rules/no-duplicate-else-if",
"lint/suspicious/noDuplicateFields": "https://biomejs.dev/linter/rules/no-duplicate-fields",
"lint/suspicious/noDuplicateFontNames": "https://biomejs.dev/linter/rules/no-font-family-duplicate-names",
Expand Down
3 changes: 2 additions & 1 deletion crates/biome_json_analyze/src/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

//! Generated file, do not edit by hand, see `xtask/codegen`

pub mod nursery;
pub mod suspicious;
::biome_analyze::declare_category! { pub Lint { kind : Lint , groups : [self :: suspicious :: Suspicious ,] } }
::biome_analyze::declare_category! { pub Lint { kind : Lint , groups : [self :: nursery :: Nursery , self :: suspicious :: Suspicious ,] } }
7 changes: 7 additions & 0 deletions crates/biome_json_analyze/src/lint/nursery.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! Generated file, do not edit by hand, see `xtask/codegen`

//! Generated file, do not edit by hand, see `xtask/codegen`

use biome_analyze::declare_lint_group;
pub mod no_duplicate_dependencies;
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_duplicate_dependencies :: NoDuplicateDependencies ,] } }
Loading