Skip to content

Conversation

@amorriscode
Copy link

@amorriscode amorriscode commented Jan 11, 2026

Summary

Extends PluginConfiguration to support an object form with path and severity fields, implementing the existing TODO in the codebase.

Example Configuration

{
  "plugins": [
    "./my-plugin.grit",
    { "path": "./other-plugin.grit", "severity": "off" }
  ]
}

Supported severity values:

  • "off": Disable the plugin entirely
  • "warn": Enable the plugin (uses plugin's own severity for now)
  • "error": Enable the plugin (default)

This allows disabling plugins per-path via overrides:

{
  "plugins": ["./my-plugin.grit"],
  "overrides": [{
    "includes": ["scripts/**"],
    "plugins": [{ "path": "./my-plugin.grit", "severity": "off" }]
  }]
}

Changes

  • Added PluginSeverity enum with Off, Warn, Error variants
  • Added PluginWithOptions struct with path and severity fields
  • Added PluginConfiguration::WithOptions variant
  • Added path(), name(), severity(), and is_enabled() methods to PluginConfiguration
  • Updated get_plugins_for_path() to merge plugin configs (override entries replace base entries with same path)
  • Updated plugin loading and filtering to respect severity: off

Test Plan

  • Added plugin_can_be_disabled_via_options test
  • Added plugin_can_be_disabled_in_override_via_options test
  • Added plugin_severity_and_enabled and plugin_name_from_path unit tests
  • All existing plugin tests pass

Known Limitations

Severity override (actually changing diagnostics from error to warn) is not yet implemented. Currently only "off" changes behavior; "warn" and "error" both enable the plugin with its own severity.

Notes

  • This PR was written primarily by Claude Code

Extends PluginConfiguration to support an object form with path and enabled fields:

```json
{
  "plugins": [
    "./my-plugin.grit",
    { "path": "./other-plugin.grit", "enabled": false }
  ]
}
```

This allows disabling plugins inline, including in overrides:

```json
{
  "plugins": ["./my-plugin.grit"],
  "overrides": [{
    "includes": ["scripts/**"],
    "plugins": [{ "path": "./my-plugin.grit", "enabled": false }]
  }]
}
```

When the same plugin path appears in both base config and overrides,
the override takes precedence.

Claude-Generated-By: Claude Code (cli/claude-opus-4-5=100%)
Claude-Steers: 1
Claude-Permission-Prompts: 3
Claude-Escapes: 0
Claude-Plan:
<claude-plan>
# Plan: Plugin Rule Configuration in Overrides

## Goal
Add support for configuring individual plugin rules (enable/disable/severity) via configuration, including in overrides.

**Target syntax:**
```json
{
  "linter": {
    "pluginRules": {
      "no-process-cwd": "off",
      "my-rule": "warn"
    }
  },
  "overrides": [{
    "includes": ["scripts/**"],
    "linter": {
      "pluginRules": { "no-process-cwd": "off" }
    }
  }]
}
```

## Background

- Plugin rules are identified by `SignalRuleKey::Plugin(name)` where name comes from the Grit pattern's `name` field
- Suppression already works via comments (`// biome-ignore lint/plugin/ruleName`)
- `TopLevelSuppression.plugins` tracks suppressed plugin names
- No configuration-based mechanism exists yet

## Implementation Approach

Use the existing suppression mechanism path (not `RuleFilter`) because:
- Plugin names are dynamic strings, not `'static` references like built-in rules
- Plugins already have their own suppression path (`suppressed_plugin()`)
- Minimal changes to core types

## Files to Modify

### 1. Configuration Schema

**`crates/biome_configuration/src/analyzer/linter/mod.rs`**
- Add `PluginRules` type: `FxHashMap<String, RulePlainConfiguration>`
- Add `plugin_rules: Option<PluginRules>` field to `LinterConfiguration`

**`crates/biome_configuration/src/overrides.rs`**
- Add `plugin_rules: Option<PluginRules>` to `OverrideLinterConfiguration`

### 2. Settings Layer

**`crates/biome_service/src/settings.rs`**
- Add `plugin_rules: Option<PluginRules>` to `LinterSettings`
- Add to `OverrideLinterSettings`
- Update `to_linter_settings()` to pass through plugin_rules
- Add `as_plugin_rules(&self, path: &Utf8Path) -> PluginRules` method to merge base + overrides

### 3. Analyzer Integration

**`crates/biome_analyze/src/options.rs`**
- Add `plugin_rules: FxHashMap<String, RulePlainConfiguration>` to `AnalyzerConfiguration`
- Add builder method `with_plugin_rules()`

**`crates/biome_analyze/src/lib.rs`**
- Modify `flush_matches()` around line 423 to check plugin rule configuration
- Handle Off/Warn/Error severities appropriately

### 4. Wire Configuration to Analyzer

**`crates/biome_service/src/file_handlers/javascript.rs`** (and other handlers)
- When building `AnalyzerConfiguration`, populate `plugin_rules` from settings

## Implementation Steps

1. **Add configuration types** - Create `PluginRules` type (`FxHashMap<String, RulePlainConfiguration>`) and add to `LinterConfiguration`
2. **Add to overrides** - Add field to `OverrideLinterConfiguration`
3. **Settings layer** - Add field to `LinterSettings`, implement merging via `as_plugin_rules(path)`
4. **Analyzer options** - Add `plugin_rules` field to `AnalyzerConfiguration`
5. **Wire handlers** - Populate `plugin_rules` in file handlers (JS, CSS, etc.)
6. **Filtering logic** - Implement severity handling in `flush_matches()`:
   - Off → skip emission
   - Warn/Error → modify diagnostic severity via `with_severity()`
7. **Tests** - Add integration tests for both disabling and severity changes

## Full Severity Support

For warn/error severity changes (not just "off"):

1. Store plugin rule config as `FxHashMap<String, RulePlainConfiguration>` (not just disabled set)
2. In `flush_matches()`, for plugin signals:
   - If `Off` → skip emission (don't call emit_signal)
   - If `Warn` or `Error` → get diagnostic via `signal.diagnostic()`, apply `with_severity()`, emit modified diagnostic
3. The `AnalyzerDiagnostic` type supports `with_severity()` via `DiagnosticExt` trait

### Implementation Detail
In `crates/biome_analyze/src/lib.rs` around line 495:
```rust
// For plugin signals, check configured severity
if let SignalRuleKey::Plugin(plugin_name) = &entry.rule {
    if let Some(config) = self.options.configuration.plugin_rules.get(plugin_name.as_ref()) {
        match config {
            RulePlainConfiguration::Off => {
                self.signal_queue.pop();
                continue;
            }
            RulePlainConfiguration::Warn | RulePlainConfiguration::Error => {
                // Modify severity before emission
                if let Some(diag) = entry.signal.diagnostic() {
                    let severity = Severity::from(*config);
                    let modified_diag = diag.with_severity(severity);
                    // Emit modified diagnostic
                }
                self.signal_queue.pop();
                continue;
            }
            _ => {} // On/Info - use default behavior
        }
    }
}
```

## Edge Cases

- **Precedence**: Config disabling takes precedence (can't re-enable via comment)
- **Override merging**: Plugin rules merge (later overrides win for same rule name)
- **Unknown names**: Consider warning for plugin names that don't exist (follow-up)

## Detailed Implementation Notes

### Configuration Types Location
- `LinterConfiguration` is at `crates/biome_configuration/src/analyzer/linter/mod.rs:19`
- `OverrideLinterConfiguration` is at `crates/biome_configuration/src/overrides.rs:182`

### AnalyzerConfiguration Location
- `AnalyzerConfiguration` is at `crates/biome_analyze/src/options.rs:57`
- Built in file handlers like `crates/biome_service/src/file_handlers/javascript.rs:380`
- Add `.with_plugin_rules(plugin_rules)` builder method

### Filtering Location
- `flush_matches()` in `crates/biome_analyze/src/lib.rs` around line 412
- Check `SignalRuleKey::Plugin(plugin)` case (line 423)

## Verification

1. Create a test Grit plugin with a named rule
2. Configure `pluginRules: { "rule-name": "off" }` in biome.json
3. Run `cargo biome-cli-dev lint` and verify the rule is suppressed
4. Add an override for a specific path and verify path-specific suppression works
5. Run existing plugin tests: `cargo test -p biome_service plugin`
6. Run `just gen-analyzer` if needed for any generated code
</claude-plan>
@changeset-bot
Copy link

changeset-bot bot commented Jan 11, 2026

🦋 Changeset detected

Latest commit: 7658c80

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 14 packages
Name Type
@biomejs/biome Minor
@biomejs/cli-win32-x64 Minor
@biomejs/cli-win32-arm64 Minor
@biomejs/cli-darwin-x64 Minor
@biomejs/cli-darwin-arm64 Minor
@biomejs/cli-linux-x64 Minor
@biomejs/cli-linux-arm64 Minor
@biomejs/cli-linux-x64-musl Minor
@biomejs/cli-linux-arm64-musl Minor
@biomejs/wasm-web Minor
@biomejs/wasm-bundler Minor
@biomejs/wasm-nodejs Minor
@biomejs/backend-jsonrpc Patch
@biomejs/js-api Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added the A-Project Area: project label Jan 11, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 11, 2026

Walkthrough

Adds per-plugin configuration and severity support: plugins may be specified as a string path or an object { path, severity }. Introduces PluginWithOptions, PluginSeverity (Off, Warn, Error), accessors on PluginConfiguration (path, name, severity, has_explicit_severity, is_enabled) and Plugins::to_severity_map() / PluginSeverityMap. Disabled plugins (severity = Off) are skipped during loading and analysis. Service settings merge override plugins by path (override replaces same-path entries). Analyzer options and emission logic now honour per-plugin severity overrides, allowing suppression or remapping of diagnostics.

Possibly related PRs

Suggested labels

A-Tooling, A-Diagnostic, L-Grit

Suggested reviewers

  • dyc3
  • ematipico
  • arendjr
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding severity option support to plugin configuration, which is the primary feature across all modified files.
Description check ✅ Passed The description is directly related to the changeset, providing clear examples and explaining the new severity feature, enum variants, and affected methods.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b93d600 and c214143.

📒 Files selected for processing (2)
  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_service/src/workspace/server.rs
🧰 Additional context used
📓 Path-based instructions (3)
crates/biome_service/src/workspace/server.rs

📄 CodeRabbit inference engine (crates/biome_service/CONTRIBUTING.md)

Use WorkspaceServer implementation for maintaining workspace state in daemon mode and CLI daemonless mode

Files:

  • crates/biome_service/src/workspace/server.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use the dbg!() macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests

Files:

  • crates/biome_service/src/workspace/server.rs
  • crates/biome_service/src/workspace.tests.rs
crates/biome_service/src/workspace*.rs

📄 CodeRabbit inference engine (crates/biome_service/CONTRIBUTING.md)

Implement the Workspace trait in the Biome Service to manage internal state of projects, including open documents, project layout instances, and module graph instances

Files:

  • crates/biome_service/src/workspace.tests.rs
🧠 Learnings (17)
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace*.rs : Implement the Workspace trait in the Biome Service to manage internal state of projects, including open documents, project layout instances, and module graph instances

Applied to files:

  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/server.rs : Use WorkspaceServer implementation for maintaining workspace state in daemon mode and CLI daemonless mode

Applied to files:

  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Implement watcher tests for workspace methods in watcher.tests.rs and end-to-end tests in LSP tests

Applied to files:

  • crates/biome_service/src/workspace/server.rs
  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use helper types from the biome_diagnostics::v2 module (CodeFrameAdvice, CommandAdvice, DiffAdvice, LogAdvice) or implement the Advices trait yourself for custom advice handling

Applied to files:

  • crates/biome_service/src/workspace/server.rs
  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Use `TypeReference` instead of `Arc` for types that reference other types to avoid stale cache issues when modules are replaced

Applied to files:

  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Build debug binaries using `cargo build --bin biome` for development and triaging

Applied to files:

  • crates/biome_service/src/workspace/server.rs
  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Import the `FormatNode` trait and implement it for your Node when creating formatters in biome_js_formatter

Applied to files:

  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/tests/specs/**/* : Create test files with `invalid` and `valid` prefixes to represent code that should and should not trigger the rule

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/Cargo.toml : Include development dependencies in `Cargo.toml` for formatter tests: `biome_formatter_test`, `biome_<language>_factory`, `biome_<language>_parser`, `biome_parser`, `biome_service`, `countme`, `iai`, `quickcheck`, `quickcheck_macros`, and `tests_macros`

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Implement the Diagnostic trait on types, or use the #[derive(Diagnostic)] procedural macro to implement the trait. Configure category, severity, description, message, location, and tags using the #[diagnostic] attribute

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Ensure the type implementing Diagnostic derives Debug

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use #[derive(Diagnostic)] on enums when every variant contains a type that is itself a diagnostic

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/crates/biome_diagnostics_categories/src/categories.rs : Register all new diagnostic categories in crates/biome_diagnostics_categories/src/categories.rs

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `diagnostic` function to provide error messages explaining what the error is, why it is triggered, and what the user should do

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Fields with #[advice] or #[verbose_advice] attributes must implement the Advices trait to record advices on the diagnostic

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Use the `dbg_write!` macro to debug formatter output instead of other logging methods

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Debug the WorkspaceWatcher by starting the daemon with cargo run --bin=biome -- start and running commands such as cargo run --bin=biome -- lint --use-server <path>

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
🔇 Additional comments (7)
crates/biome_service/src/workspace/server.rs (2)

40-40: LGTM! Import consolidation aligns with the new plugin API.

The shift from importing PluginConfiguration to importing Plugins alongside BiomePlugin, PluginCache, and PluginDiagnostic reflects the API changes described in the PR objectives.


677-701: Good implementation of disabled plugin skipping.

The logic correctly skips loading disabled plugins (lines 682-685), which prevents errors when plugin files are missing. The path handling change on line 690 (from clone().into() to to_string().into()) suggests plugin_config.path() now returns a string reference rather than an owned String, which is appropriate.

crates/biome_service/src/workspace.tests.rs (5)

14-14: LGTM! Imports updated for new plugin configuration options.


678-753: Well-structured test for disabled plugins.

The test correctly verifies that plugins configured with severity: Off don't produce diagnostics. Clear setup and appropriate assertions.


755-875: Excellent coverage of per-path override behaviour.

The test thoroughly validates that overrides can disable plugins for specific paths whilst keeping them enabled globally. Good use of assertions to verify both enabled and disabled cases.


966-1006: Excellent test for graceful handling of missing disabled plugins.

This test ensures that disabled plugins with missing files don't cause errors, which is important for user experience. The setup correctly omits creating the plugin file (line 971) and verifies that configuration succeeds.


877-964: The severity override feature is fully implemented—no action needed.

The code shows that PluginSeverity::Warn is properly supported: the configuration is parsed correctly, to_diagnostic_severity() correctly converts it to Severity::Warning, and the severity map is passed to all analysers. The test is valid and the assertion on line 960 should pass. The PR limitation note appears to be outdated.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/biome_service/src/workspace/server.rs (1)

677-689: Fix plugin loading: respect enabled and pass the right path type.

  1. Disabled plugins are still loaded here, which can surface load errors for configs that are explicitly disabled.
  2. BiomePlugin::load takes &Utf8Path (per the snippet in crates/biome_plugin_loader/src/lib.rs), but plugin_config.path() is used as if it were already that type.
Proposed fix
 fn load_plugins(&self, base_path: &Utf8Path, plugins: &Plugins) -> Vec<PluginDiagnostic> {
     let mut diagnostics = Vec::new();
     let plugin_cache = PluginCache::default();

     for plugin_config in plugins.iter() {
-        let plugin_path = plugin_config.path();
-        match BiomePlugin::load(self.fs.clone(), plugin_path, base_path) {
-            Ok((plugin, _)) => {
-                plugin_cache.insert_plugin(plugin_path.to_string().into(), plugin);
-            }
+        if !plugin_config.is_enabled() {
+            continue;
+        }
+
+        let plugin_path = Utf8Path::new(plugin_config.path());
+        match BiomePlugin::load(self.fs.clone(), plugin_path, base_path) {
+            Ok((plugin, resolved_path)) => {
+                plugin_cache.insert_plugin(resolved_path, plugin);
+            }
             Err(diagnostic) => diagnostics.push(diagnostic),
         }
     }
🤖 Fix all issues with AI agents
In @.changeset/plugin-enabled-option.md:
- Around line 5-16: Update the changelog text to explicitly state the default
behavior of the new `enabled` option: clarify that if `enabled` is omitted it is
treated as true (i.e., plugins are enabled by default) and only `enabled: false`
disables a plugin; reference the `enabled` field and the example object form so
readers understand that leaving out `enabled` means the plugin remains enabled
and that overrides still take precedence.

In @crates/biome_plugin_loader/src/configuration.rs:
- Around line 95-106: The PluginWithOptions struct currently allows an empty
path because of #[serde(default)] on the path field; remove #[serde(default)]
from the path field to make it required during deserialization, or (if you need
a default) keep the attribute but implement validation in the Deserializable
impl for PluginWithOptions to check that the path string is not empty and return
an error when it is; update tests accordingly to assert that deserializing `{
"enabled": false }` fails and that valid configs succeed.
🧹 Nitpick comments (3)
crates/biome_plugin_loader/src/plugin_cache.rs (1)

22-54: Skip-disabled logic looks good; suffix lookup may be ambiguous.

Skipping disabled plugin configs before emitting not_loaded diagnostics is the right UX.

One concern: map.iter().find(|(path, _)| path.ends_with(...)) can pick an arbitrary match if multiple cached plugin paths share the same suffix (and iteration order is not stable), which could lead to the “wrong” plugin being used. If that’s a real possibility, consider keying the cache by the fully resolved path and doing an exact lookup.

crates/biome_service/src/workspace.tests.rs (1)

678-875: Good coverage; consider adding “disabled + missing file = no error” regression.

These tests validate the main behaviour (global disable + override disable) well.

One extra test that would harden semantics: configure a plugin with enabled: false and a non-existent path, and assert update_settings doesn’t error and no “plugin not loaded” diagnostics appear. That would catch accidental “we still try to load disabled plugins” regressions.

crates/biome_plugin_loader/src/configuration.rs (1)

77-93: Consider adding doc tests.

The accessor methods are well-implemented with sensible defaults. Per the coding guidelines, consider adding doc test examples in the rustdoc comments to demonstrate usage:

/// Returns the path to the plugin file
///
/// # Examples
///
/// ```
/// use biome_plugin_loader::configuration::PluginConfiguration;
/// 
/// let config = PluginConfiguration::Path("./my-plugin.grit".into());
/// assert_eq!(config.path(), "./my-plugin.grit");
/// ```
pub fn path(&self) -> &str {
    // ...
}

As per coding guidelines, use doc tests (doctest) format with code blocks in rustdoc comments.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95aba98 and 9c9687a.

📒 Files selected for processing (6)
  • .changeset/plugin-enabled-option.md
  • crates/biome_plugin_loader/src/configuration.rs
  • crates/biome_plugin_loader/src/plugin_cache.rs
  • crates/biome_service/src/settings.rs
  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_service/src/workspace/server.rs
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use the dbg!() macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests

Files:

  • crates/biome_plugin_loader/src/configuration.rs
  • crates/biome_plugin_loader/src/plugin_cache.rs
  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_service/src/workspace/server.rs
  • crates/biome_service/src/settings.rs
crates/biome_service/src/workspace*.rs

📄 CodeRabbit inference engine (crates/biome_service/CONTRIBUTING.md)

Implement the Workspace trait in the Biome Service to manage internal state of projects, including open documents, project layout instances, and module graph instances

Files:

  • crates/biome_service/src/workspace.tests.rs
crates/biome_service/src/workspace/server.rs

📄 CodeRabbit inference engine (crates/biome_service/CONTRIBUTING.md)

Use WorkspaceServer implementation for maintaining workspace state in daemon mode and CLI daemonless mode

Files:

  • crates/biome_service/src/workspace/server.rs
🧠 Learnings (29)
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Use `Option<_>` wrapper for rule option fields to enable proper merging of configurations

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_service/src/settings.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Implement `biome_deserialize::Merge` for rule option types to define how shared and user configurations are merged

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
  • crates/biome_service/src/settings.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(rename_all = "camelCase")]` to rule option structs to match JSON configuration naming convention

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
  • crates/biome_service/src/workspace/server.rs
  • crates/biome_service/src/settings.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(deny_unknown_fields)]` to rule option structs to enforce strict configuration validation

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
  • crates/biome_service/src/settings.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Rule option types must derive `Deserializable`, `Serialize`, `Deserialize`, and optionally `JsonSchema` traits

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use helper functions like `map`, `filter`, and `and_then` to avoid excessive nested `if let` statements

Applied to files:

  • crates/biome_plugin_loader/src/plugin_cache.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Implement watcher tests for workspace methods in watcher.tests.rs and end-to-end tests in LSP tests

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/Cargo.toml : Include development dependencies in `Cargo.toml` for formatter tests: `biome_formatter_test`, `biome_<language>_factory`, `biome_<language>_parser`, `biome_parser`, `biome_service`, `countme`, `iai`, `quickcheck`, `quickcheck_macros`, and `tests_macros`

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/tests/specs/**/* : Create test files with `invalid` and `valid` prefixes to represent code that should and should not trigger the rule

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/tests/spec_tests.rs : Use the `tests_macros::gen_tests!` macro in `spec_tests.rs` to generate test functions for each specification file matching the pattern `tests/specs/<language>/**/*.<ext>`

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Ensure the type implementing Diagnostic derives Debug

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Implement the Diagnostic trait on types, or use the #[derive(Diagnostic)] procedural macro to implement the trait. Configure category, severity, description, message, location, and tags using the #[diagnostic] attribute

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use helper types from the biome_diagnostics::v2 module (CodeFrameAdvice, CommandAdvice, DiffAdvice, LogAdvice) or implement the Advices trait yourself for custom advice handling

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use #[derive(Diagnostic)] on enums when every variant contains a type that is itself a diagnostic

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Build debug binaries using `cargo build --bin biome` for development and triaging

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/crates/biome_diagnostics_categories/src/categories.rs : Register all new diagnostic categories in crates/biome_diagnostics_categories/src/categories.rs

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `diagnostic` function to provide error messages explaining what the error is, why it is triggered, and what the user should do

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Fields with #[advice] or #[verbose_advice] attributes must implement the Advices trait to record advices on the diagnostic

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Debug the WorkspaceWatcher by starting the daemon with cargo run --bin=biome -- start and running commands such as cargo run --bin=biome -- lint --use-server <path>

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Use the `dbg_write!` macro to debug formatter output instead of other logging methods

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace*.rs : Implement the Workspace trait in the Biome Service to manage internal state of projects, including open documents, project layout instances, and module graph instances

Applied to files:

  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Use `TypeReference` instead of `Arc` for types that reference other types to avoid stale cache issues when modules are replaced

Applied to files:

  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Store type data in linear vectors instead of using recursive data structures with `Arc` for improved data locality and performance

Applied to files:

  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/server.rs : Use WorkspaceServer implementation for maintaining workspace state in daemon mode and CLI daemonless mode

Applied to files:

  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_node_union!` macro to query multiple node types together to avoid redundant traversal passes

Applied to files:

  • crates/biome_service/src/workspace/server.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Import the `FormatNode` trait and implement it for your Node when creating formatters in biome_js_formatter

Applied to files:

  • crates/biome_service/src/workspace/server.rs
  • crates/biome_service/src/settings.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/src/context.rs : Define `<Language>FormatContext` struct in a `context.rs` file containing `comments` and `source_map` fields, implementing `FormatContext` and `CstFormatContext` traits

Applied to files:

  • crates/biome_service/src/settings.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/src/lib.rs : Expose a public `format_node` function that accepts formatting options and a root syntax node, returning a `FormatResult<Formatted<Context>>` with appropriate documentation

Applied to files:

  • crates/biome_service/src/settings.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/src/lib.rs : Define a type alias `<Language>Formatter<'buf>` as `Formatter<'buf, <Language>FormatContext>` in the main formatter crate

Applied to files:

  • crates/biome_service/src/settings.rs
🧬 Code graph analysis (3)
crates/biome_plugin_loader/src/plugin_cache.rs (2)
crates/biome_plugin_loader/src/configuration.rs (1)
  • path (79-84)
crates/biome_plugin_loader/src/diagnostics.rs (1)
  • not_loaded (111-121)
crates/biome_service/src/workspace/server.rs (2)
crates/biome_plugin_loader/src/lib.rs (1)
  • load (43-121)
crates/biome_plugin_loader/src/analyzer_grit_plugin.rs (1)
  • load (27-42)
crates/biome_service/src/settings.rs (1)
crates/biome_plugin_loader/src/configuration.rs (1)
  • path (79-84)
🔇 Additional comments (6)
crates/biome_service/src/workspace.tests.rs (1)

14-15: Import update makes sense.

Nice to see PluginWithOptions exercised via real workspace flows.

crates/biome_service/src/settings.rs (1)

283-317: Merge behaviour matches the PR goal; double-check precedence across multiple overrides.

Replacing by path() is a good fit for “override replaces base” semantics.

Just sanity-check that pattern ordering is the intended precedence model: since this iterates patterns in-order, later matching override patterns will win (because they replace again). If Biome’s general “last override wins” rule is relied on elsewhere, this is consistent; if not, consider iterating .rev() and doing first-match-wins for replacements.

crates/biome_plugin_loader/src/configuration.rs (4)

29-41: Clean handling of both variants.

The pattern matching to extract a mutable reference works well for both Path and WithOptions, keeping the normalization logic unified.


71-75: LGTM!

The untagged serde attribute correctly enables deserialisation of either a string or an object, maintaining backwards compatibility.


114-122: LGTM!

The deserialization correctly routes string inputs to Path and map inputs to WithOptions, enabling flexible configuration formats.


162-200: Excellent test coverage.

The tests thoroughly verify normalisation behaviour with options, default enablement semantics, and edge cases. Well done!

Extends PluginConfiguration to support an object form with path and severity fields:

```json
{
  "plugins": [
    "./my-plugin.grit",
    { "path": "./other-plugin.grit", "severity": "off" }
  ]
}
```

Supported severity values:
- "off": Disable the plugin entirely
- "warn": Enable the plugin (uses plugin's own severity for now)
- "error": Enable the plugin (default, uses plugin's own severity)

This allows disabling plugins per-path via overrides:

```json
{
  "plugins": ["./my-plugin.grit"],
  "overrides": [{
    "includes": ["scripts/**"],
    "plugins": [{ "path": "./my-plugin.grit", "severity": "off" }]
  }]
}
```

Note: severity override (changing warn to error or vice versa) is not yet
implemented. Currently only "off" actually changes behavior.

Claude-Generated-By: Claude Code (cli/claude-opus-4-5=100%)
Claude-Steers: 0
Claude-Permission-Prompts: 1
Claude-Escapes: 0
Claude-Plan:
<claude-plan>
# Plan: Plugin Rule Configuration in Overrides

## Goal
Add support for configuring individual plugin rules (enable/disable/severity) via configuration, including in overrides.

**Target syntax:**
```json
{
  "linter": {
    "pluginRules": {
      "no-process-cwd": "off",
      "my-rule": "warn"
    }
  },
  "overrides": [{
    "includes": ["scripts/**"],
    "linter": {
      "pluginRules": { "no-process-cwd": "off" }
    }
  }]
}
```

## Background

- Plugin rules are identified by `SignalRuleKey::Plugin(name)` where name comes from the Grit pattern's `name` field
- Suppression already works via comments (`// biome-ignore lint/plugin/ruleName`)
- `TopLevelSuppression.plugins` tracks suppressed plugin names
- No configuration-based mechanism exists yet

## Implementation Approach

Use the existing suppression mechanism path (not `RuleFilter`) because:
- Plugin names are dynamic strings, not `'static` references like built-in rules
- Plugins already have their own suppression path (`suppressed_plugin()`)
- Minimal changes to core types

## Files to Modify

### 1. Configuration Schema

**`crates/biome_configuration/src/analyzer/linter/mod.rs`**
- Add `PluginRules` type: `FxHashMap<String, RulePlainConfiguration>`
- Add `plugin_rules: Option<PluginRules>` field to `LinterConfiguration`

**`crates/biome_configuration/src/overrides.rs`**
- Add `plugin_rules: Option<PluginRules>` to `OverrideLinterConfiguration`

### 2. Settings Layer

**`crates/biome_service/src/settings.rs`**
- Add `plugin_rules: Option<PluginRules>` to `LinterSettings`
- Add to `OverrideLinterSettings`
- Update `to_linter_settings()` to pass through plugin_rules
- Add `as_plugin_rules(&self, path: &Utf8Path) -> PluginRules` method to merge base + overrides

### 3. Analyzer Integration

**`crates/biome_analyze/src/options.rs`**
- Add `plugin_rules: FxHashMap<String, RulePlainConfiguration>` to `AnalyzerConfiguration`
- Add builder method `with_plugin_rules()`

**`crates/biome_analyze/src/lib.rs`**
- Modify `flush_matches()` around line 423 to check plugin rule configuration
- Handle Off/Warn/Error severities appropriately

### 4. Wire Configuration to Analyzer

**`crates/biome_service/src/file_handlers/javascript.rs`** (and other handlers)
- When building `AnalyzerConfiguration`, populate `plugin_rules` from settings

## Implementation Steps

1. **Add configuration types** - Create `PluginRules` type (`FxHashMap<String, RulePlainConfiguration>`) and add to `LinterConfiguration`
2. **Add to overrides** - Add field to `OverrideLinterConfiguration`
3. **Settings layer** - Add field to `LinterSettings`, implement merging via `as_plugin_rules(path)`
4. **Analyzer options** - Add `plugin_rules` field to `AnalyzerConfiguration`
5. **Wire handlers** - Populate `plugin_rules` in file handlers (JS, CSS, etc.)
6. **Filtering logic** - Implement severity handling in `flush_matches()`:
   - Off → skip emission
   - Warn/Error → modify diagnostic severity via `with_severity()`
7. **Tests** - Add integration tests for both disabling and severity changes

## Full Severity Support

For warn/error severity changes (not just "off"):

1. Store plugin rule config as `FxHashMap<String, RulePlainConfiguration>` (not just disabled set)
2. In `flush_matches()`, for plugin signals:
   - If `Off` → skip emission (don't call emit_signal)
   - If `Warn` or `Error` → get diagnostic via `signal.diagnostic()`, apply `with_severity()`, emit modified diagnostic
3. The `AnalyzerDiagnostic` type supports `with_severity()` via `DiagnosticExt` trait

### Implementation Detail
In `crates/biome_analyze/src/lib.rs` around line 495:
```rust
// For plugin signals, check configured severity
if let SignalRuleKey::Plugin(plugin_name) = &entry.rule {
    if let Some(config) = self.options.configuration.plugin_rules.get(plugin_name.as_ref()) {
        match config {
            RulePlainConfiguration::Off => {
                self.signal_queue.pop();
                continue;
            }
            RulePlainConfiguration::Warn | RulePlainConfiguration::Error => {
                // Modify severity before emission
                if let Some(diag) = entry.signal.diagnostic() {
                    let severity = Severity::from(*config);
                    let modified_diag = diag.with_severity(severity);
                    // Emit modified diagnostic
                }
                self.signal_queue.pop();
                continue;
            }
            _ => {} // On/Info - use default behavior
        }
    }
}
```

## Edge Cases

- **Precedence**: Config disabling takes precedence (can't re-enable via comment)
- **Override merging**: Plugin rules merge (later overrides win for same rule name)
- **Unknown names**: Consider warning for plugin names that don't exist (follow-up)

## Detailed Implementation Notes

### Configuration Types Location
- `LinterConfiguration` is at `crates/biome_configuration/src/analyzer/linter/mod.rs:19`
- `OverrideLinterConfiguration` is at `crates/biome_configuration/src/overrides.rs:182`

### AnalyzerConfiguration Location
- `AnalyzerConfiguration` is at `crates/biome_analyze/src/options.rs:57`
- Built in file handlers like `crates/biome_service/src/file_handlers/javascript.rs:380`
- Add `.with_plugin_rules(plugin_rules)` builder method

### Filtering Location
- `flush_matches()` in `crates/biome_analyze/src/lib.rs` around line 412
- Check `SignalRuleKey::Plugin(plugin)` case (line 423)

## Verification

1. Create a test Grit plugin with a named rule
2. Configure `pluginRules: { "rule-name": "off" }` in biome.json
3. Run `cargo biome-cli-dev lint` and verify the rule is suppressed
4. Add an override for a specific path and verify path-specific suppression works
5. Run existing plugin tests: `cargo test -p biome_service plugin`
6. Run `just gen-analyzer` if needed for any generated code
</claude-plan>
@github-actions github-actions bot added the A-Linter Area: linter label Jan 11, 2026
@amorriscode amorriscode changed the title feat(plugins): add enabled option to plugin configuration feat(plugins): add severity option to plugin configuration Jan 11, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @crates/biome_plugin_loader/src/configuration.rs:
- Around line 212-281: Update the misleading comment in the test function
plugin_can_be_disabled_via_options so it reflects that the plugin is disabled
via severity: Some(PluginSeverity::Off) rather than saying “enabled: false”;
locate the test (plugin_can_be_disabled_via_options) and change the comment to
state that the plugin is disabled because severity is Off (e.g., “disabled via
severity Off”) so the comment matches the test configuration.
- Around line 144-156: The path field on struct PluginWithOptions currently has
#[serde(default)] causing missing paths to deserialize as empty strings; remove
the #[serde(default)] attribute from the pub path: String field so
deserialization requires path to be present (it will then error if missing), and
run/update any deserialization tests or callers that relied on an implicit
default; keep serde(rename_all = "camelCase", deny_unknown_fields) as-is so
missing path surfaces as an error.
🧹 Nitpick comments (5)
crates/biome_plugin_loader/src/configuration.rs (2)

19-33: to_severity_map() keying by name() can collide (same file stem, different paths).
If you ever allow multiple plugins with identical stems (e.g. a/plugin.grit and b/plugin.grit), one entry will silently win in the map (Line 31-32). Consider keying by canonicalised path (or explicitly document “plugin name must be unique”).


158-173: Consider reporting invalid plugin config types instead of silently returning None.
For non-string/non-map values you currently return None (Line 171-172). If the surrounding config system treats None as “ignore”, this can mask user typos. If possible, emit a diagnostic via ctx here.

crates/biome_analyze/src/options.rs (2)

86-90: Public field vs the rest of AnalyzerConfiguration is a bit inconsistent.
plugin_severities is pub while most configuration is private-ish (Line 89). If you want to keep invariants tighter, consider pub(crate) plus an accessor, and keep the builder as the public API.

Also applies to: 131-134


213-222: The Option<Option<Severity>> return type is accurate, but awkward to consume.
Consider adding a tiny helper like is_plugin_enabled(name) -> Option<bool> or plugin_effective_severity(name) -> Option<Severity> (where “off” returns None) to avoid double-Option handling everywhere.

crates/biome_service/src/workspace.tests.rs (1)

755-875: Override test is valuable; consider asserting both files’ total diagnostics too.
Right now you filter by category().name() == "plugin" (Line 845-870). If anything else starts emitting diagnostics in these fixtures, the test could pass while the user experience regresses. A lightweight assert_eq!(result_x.diagnostics.len(), …) would make this more robust.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9c9687a and 3f96af2.

📒 Files selected for processing (5)
  • .changeset/plugin-enabled-option.md
  • crates/biome_analyze/src/lib.rs
  • crates/biome_analyze/src/options.rs
  • crates/biome_plugin_loader/src/configuration.rs
  • crates/biome_service/src/workspace.tests.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • .changeset/plugin-enabled-option.md
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use the dbg!() macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests

Files:

  • crates/biome_analyze/src/lib.rs
  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
  • crates/biome_plugin_loader/src/configuration.rs
crates/biome_service/src/workspace*.rs

📄 CodeRabbit inference engine (crates/biome_service/CONTRIBUTING.md)

Implement the Workspace trait in the Biome Service to manage internal state of projects, including open documents, project layout instances, and module graph instances

Files:

  • crates/biome_service/src/workspace.tests.rs
🧠 Learnings (33)
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Use `Option<_>` wrapper for rule option fields to enable proper merging of configurations

Applied to files:

  • crates/biome_analyze/src/lib.rs
  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(rename_all = "camelCase")]` to rule option structs to match JSON configuration naming convention

Applied to files:

  • crates/biome_analyze/src/lib.rs
  • crates/biome_analyze/src/options.rs
  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Rule options must be defined in the `biome_rule_options` crate with a file named after the rule

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Implement `biome_deserialize::Merge` for rule option types to define how shared and user configurations are merged

Applied to files:

  • crates/biome_analyze/src/lib.rs
  • crates/biome_analyze/src/options.rs
  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(deny_unknown_fields)]` to rule option structs to enforce strict configuration validation

Applied to files:

  • crates/biome_analyze/src/lib.rs
  • crates/biome_analyze/src/options.rs
  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Deprecated rules must include a `deprecated` field in the `declare_lint_rule!` macro with an explanation of what rule to use instead

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use helper functions like `map`, `filter`, and `and_then` to avoid excessive nested `if let` statements

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Rule option types must derive `Deserializable`, `Serialize`, `Deserialize`, and optionally `JsonSchema` traits

Applied to files:

  • crates/biome_analyze/src/lib.rs
  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Use `Box<[Box<str>]>` instead of `Vec<String>` for collections of strings in rule options to save memory

Applied to files:

  • crates/biome_analyze/src/lib.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_lint_rule!` macro with a `version` field set to `next` for new rules

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use the `Semantic<T>` query type to access semantic information about bindings, references, and scope within a rule

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement custom `Queryable` and `Visitor` types for rules that require deep inspection of child nodes to avoid inefficient traversals

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `rule_category!()` macro to refer to the diagnostic category instead of dynamically parsing its string name

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `use` prefix when the rule's sole intention is to mandate a single concept

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `ctx.get_service()` to retrieve services by type when a rule requires multiple services beyond those pulled in the Query

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : When porting rules from other linters, use `sources` metadata with `RuleSource::Eslint().same()` for identical behavior or `.inspired()` for different behavior

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Invalid code snippets in rule documentation must emit exactly one diagnostic

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `diagnostic` function to provide error messages explaining what the error is, why it is triggered, and what the user should do

Applied to files:

  • crates/biome_analyze/src/lib.rs
  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Check if a variable is global using the semantic model before reporting diagnostics for rules that ban global functions or variables

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Implement watcher tests for workspace methods in watcher.tests.rs and end-to-end tests in LSP tests

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Implement the Diagnostic trait on types, or use the #[derive(Diagnostic)] procedural macro to implement the trait. Configure category, severity, description, message, location, and tags using the #[diagnostic] attribute

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Ensure the type implementing Diagnostic derives Debug

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use helper types from the biome_diagnostics::v2 module (CodeFrameAdvice, CommandAdvice, DiffAdvice, LogAdvice) or implement the Advices trait yourself for custom advice handling

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use #[derive(Diagnostic)] on enums when every variant contains a type that is itself a diagnostic

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Build debug binaries using `cargo build --bin biome` for development and triaging

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/crates/biome_diagnostics_categories/src/categories.rs : Register all new diagnostic categories in crates/biome_diagnostics_categories/src/categories.rs

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Fields with #[advice] or #[verbose_advice] attributes must implement the Advices trait to record advices on the diagnostic

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Use the `dbg_write!` macro to debug formatter output instead of other logging methods

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Debug the WorkspaceWatcher by starting the daemon with cargo run --bin=biome -- start and running commands such as cargo run --bin=biome -- lint --use-server <path>

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-12-31T15:19:03.056Z
Learnt from: Netail
Repo: biomejs/biome PR: 8631
File: crates/biome_cli/src/reporter/sarif.rs:197-218
Timestamp: 2025-12-31T15:19:03.056Z
Learning: In SARIF 2.1.0 reporter (crates/biome_cli/src/reporter/sarif.rs), when location data (source_code or span) is unavailable, omit the region field entirely using Option and #[serde(skip_serializing_if = "Option::is_none")] rather than defaulting to 0 values, as the SARIF spec states "If the region property is absent, the physicalLocation object refers to the entire artifact."

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Do not attempt to 'fix' the code; if a token/node is known to be mandatory but is missing, return `None` instead

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2025-12-31T15:35:41.261Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8639
File: crates/biome_js_analyze/src/lint/nursery/no_excessive_lines_per_file.rs:101-108
Timestamp: 2025-12-31T15:35:41.261Z
Learning: In crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs, the `issue_number` field in `declare_lint_rule!` macro is optional and the vast majority of nursery rules do not need it. Do not recommend adding `issue_number` unless there's a specific reason.

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Store type data in linear vectors instead of using recursive data structures with `Arc` for improved data locality and performance

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
🧬 Code graph analysis (2)
crates/biome_service/src/workspace.tests.rs (1)
crates/biome_plugin_loader/src/configuration.rs (2)
  • path (91-96)
  • severity (105-110)
crates/biome_analyze/src/options.rs (1)
packages/@biomejs/plugin-api/index.d.ts (1)
  • Severity (1-1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Validate PR title
  • GitHub Check: Validate PR title
🔇 Additional comments (8)
crates/biome_plugin_loader/src/configuration.rs (3)

39-54: Path normalisation update looks solid.
The match to unify Path and WithOptions handling keeps the logic tidy and avoids duplicating the normalisation code (Line 41-53).


89-116: name()/severity()/is_enabled() are nice ergonomics, but please sanity-check Windows paths.
Utf8Path::new(path).file_stem() (Line 101) won’t treat backslashes as separators, so a user-provided ".\\plugin.grit" may produce a surprising “name”. If Windows config commonly uses \, consider normalising separators (or documenting forward slashes only).


118-142: PluginSeverity::to_diagnostic_severity() is a clean bridge.
Returning None for Off (Line 135-141) is a good way to represent “skip emission” without needing a sentinel value elsewhere.

crates/biome_analyze/src/lib.rs (1)

41-43: Re-export is straightforward and keeps the public API coherent.
Nothing spooky here; just ensure the name PluginSeverityMap doesn’t confuse users given there’s also a similarly-named type in biome_plugin_loader.

crates/biome_analyze/src/options.rs (2)

10-13: PluginSeverityMap shape makes sense for the analyser (Option = off).
The “None means off, Some(severity) means override” contract is crisp (Line 10-12).


1-3: The plugin configuration design is correct and intentional. The external format uses a severity field (with values "off", "warn", "error") rather than an enabled boolean, which is superior because it allows three distinct states instead of binary on/off control. The code properly converts:

  • User config: { "path": "./plugin.grit", "severity": "off" }
  • Plugin loader: PluginSeverity::Off
  • Analyzer: Option<Severity> via to_diagnostic_severity()

The mapping is intentional, documented (line 153), and semantically sound. No compatibility layer needed.

Likely an incorrect or invalid review comment.

crates/biome_service/src/workspace.tests.rs (2)

14-15: Imports updated cleanly for the new config shape.
Nothing to add, other than: nice to see the tests exercising the public surface rather than reaching into internals.


678-753: Good coverage: disabled plugin produces no plugin diagnostics.
This test asserts behaviour rather than implementation details, which is exactly what you want here (Line 743-752).

Comment on lines +144 to 165
/// Plugin configuration with additional options
#[derive(Clone, Debug, Default, Deserialize, Deserializable, Eq, PartialEq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct PluginWithOptions {
/// Path to the plugin file
#[serde(default)]
pub path: String,
/// Severity level for the plugin's diagnostics.
/// Use "off" to disable, "warn" for warnings, "error" for errors (default).
#[serde(skip_serializing_if = "Option::is_none")]
pub severity: Option<PluginSeverity>,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's read the specific file and lines mentioned in the review
cat -n crates/biome_plugin_loader/src/configuration.rs | sed -n '140,160p'

Repository: biomejs/biome

Length of output: 930


🏁 Script executed:

# Search for all usages of PluginWithOptions in the codebase
rg "PluginWithOptions" -B 2 -A 2

Repository: biomejs/biome

Length of output: 5130


🏁 Script executed:

# Check if there are any JSON examples or tests that might be affected
rg "PluginWithOptions\|path.*severity" --type rs -A 3

Repository: biomejs/biome

Length of output: 83


🏁 Script executed:

# Search for test files and JSON examples related to plugins
fd -e json -e toml | xargs rg -l "plugin" 2>/dev/null | head -20

Repository: biomejs/biome

Length of output: 552


🏁 Script executed:

# Look for deserialization tests in configuration.rs
cat -n crates/biome_plugin_loader/src/configuration.rs | grep -A 20 "deserialize\|from_json\|#\[test\]" | head -80

Repository: biomejs/biome

Length of output: 3337


🏁 Script executed:

# Check if there are any integration tests with JSON config
rg "PluginWithOptions.*severity.*path\|path.*severity" -B 5 -A 5 --type-list | head -60

Repository: biomejs/biome

Length of output: 446


🏁 Script executed:

# Search for deserialization context or from string methods
rg "deserialize|from_str" crates/biome_plugin_loader/src/configuration.rs -B 2 -A 5

Repository: biomejs/biome

Length of output: 1067


🏁 Script executed:

# Look for biome.json config files with plugin examples
find . -name "biome.json" -o -name "*.biome.json" | xargs cat 2>/dev/null

Repository: biomejs/biome

Length of output: 6497


🏁 Script executed:

# Search for path validation or error handling in the loader
rg "path.*is_empty\|empty.*path\|plugin.*error" crates/biome_plugin_loader/ -B 2 -A 2

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Check if deny_unknown_fields affects the deserialization behavior
rg "deny_unknown_fields" crates/biome_plugin_loader/src/configuration.rs -B 3 -A 3

Repository: biomejs/biome

Length of output: 998


🏁 Script executed:

# Look for any documentation or comments about the serde(default) usage
rg -B 5 -A 5 "serde\(default\)" crates/biome_plugin_loader/

Repository: biomejs/biome

Length of output: 1127


Remove #[serde(default)] to make path required.

The path field should not default to an empty string; missing path should error during deserialization rather than failing cryptically later. Since path is String (not Option), it's clearly intended as mandatory.

Proposed fix
 pub struct PluginWithOptions {
     /// Path to the plugin file
-    #[serde(default)]
     pub path: String,
📝 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
/// Plugin configuration with additional options
#[derive(Clone, Debug, Default, Deserialize, Deserializable, Eq, PartialEq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct PluginWithOptions {
/// Path to the plugin file
#[serde(default)]
pub path: String,
/// Severity level for the plugin's diagnostics.
/// Use "off" to disable, "warn" for warnings, "error" for errors (default).
#[serde(skip_serializing_if = "Option::is_none")]
pub severity: Option<PluginSeverity>,
}
/// Plugin configuration with additional options
#[derive(Clone, Debug, Default, Deserialize, Deserializable, Eq, PartialEq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct PluginWithOptions {
/// Path to the plugin file
pub path: String,
/// Severity level for the plugin's diagnostics.
/// Use "off" to disable, "warn" for warnings, "error" for errors (default).
#[serde(skip_serializing_if = "Option::is_none")]
pub severity: Option<PluginSeverity>,
}
🤖 Prompt for AI Agents
In @crates/biome_plugin_loader/src/configuration.rs around lines 144 - 156, The
path field on struct PluginWithOptions currently has #[serde(default)] causing
missing paths to deserialize as empty strings; remove the #[serde(default)]
attribute from the pub path: String field so deserialization requires path to be
present (it will then error if missing), and run/update any deserialization
tests or callers that relied on an implicit default; keep serde(rename_all =
"camelCase", deny_unknown_fields) as-is so missing path surfaces as an error.

Apply severity override at signal creation time in analyzer_plugin.rs.
When a plugin has an explicit severity config (warn/error), we override
the diagnostic's severity before creating the signal. This allows:

- `severity: "off"` - Skip diagnostics entirely (already worked)
- `severity: "warn"` - Override to Warning severity
- `severity: "error"` - Override to Error severity (default)

Plugins without explicit severity config continue to use their inline
severity from the Grit pattern (e.g., `severity = "warn"`).

Added plugin_severities to all file handlers for consistency.

Claude-Generated-By: Claude Code (cli/claude-opus-4-5=100%)
Claude-Steers: 0
Claude-Permission-Prompts: 3
Claude-Escapes: 0
Claude-Plan:
<claude-plan>
# Plan: Plugin Rule Configuration in Overrides

## Goal
Add support for configuring individual plugin rules (enable/disable/severity) via configuration, including in overrides.

**Target syntax:**
```json
{
  "linter": {
    "pluginRules": {
      "no-process-cwd": "off",
      "my-rule": "warn"
    }
  },
  "overrides": [{
    "includes": ["scripts/**"],
    "linter": {
      "pluginRules": { "no-process-cwd": "off" }
    }
  }]
}
```

## Background

- Plugin rules are identified by `SignalRuleKey::Plugin(name)` where name comes from the Grit pattern's `name` field
- Suppression already works via comments (`// biome-ignore lint/plugin/ruleName`)
- `TopLevelSuppression.plugins` tracks suppressed plugin names
- No configuration-based mechanism exists yet

## Implementation Approach

Use the existing suppression mechanism path (not `RuleFilter`) because:
- Plugin names are dynamic strings, not `'static` references like built-in rules
- Plugins already have their own suppression path (`suppressed_plugin()`)
- Minimal changes to core types

## Files to Modify

### 1. Configuration Schema

**`crates/biome_configuration/src/analyzer/linter/mod.rs`**
- Add `PluginRules` type: `FxHashMap<String, RulePlainConfiguration>`
- Add `plugin_rules: Option<PluginRules>` field to `LinterConfiguration`

**`crates/biome_configuration/src/overrides.rs`**
- Add `plugin_rules: Option<PluginRules>` to `OverrideLinterConfiguration`

### 2. Settings Layer

**`crates/biome_service/src/settings.rs`**
- Add `plugin_rules: Option<PluginRules>` to `LinterSettings`
- Add to `OverrideLinterSettings`
- Update `to_linter_settings()` to pass through plugin_rules
- Add `as_plugin_rules(&self, path: &Utf8Path) -> PluginRules` method to merge base + overrides

### 3. Analyzer Integration

**`crates/biome_analyze/src/options.rs`**
- Add `plugin_rules: FxHashMap<String, RulePlainConfiguration>` to `AnalyzerConfiguration`
- Add builder method `with_plugin_rules()`

**`crates/biome_analyze/src/lib.rs`**
- Modify `flush_matches()` around line 423 to check plugin rule configuration
- Handle Off/Warn/Error severities appropriately

### 4. Wire Configuration to Analyzer

**`crates/biome_service/src/file_handlers/javascript.rs`** (and other handlers)
- When building `AnalyzerConfiguration`, populate `plugin_rules` from settings

## Implementation Steps

1. **Add configuration types** - Create `PluginRules` type (`FxHashMap<String, RulePlainConfiguration>`) and add to `LinterConfiguration`
2. **Add to overrides** - Add field to `OverrideLinterConfiguration`
3. **Settings layer** - Add field to `LinterSettings`, implement merging via `as_plugin_rules(path)`
4. **Analyzer options** - Add `plugin_rules` field to `AnalyzerConfiguration`
5. **Wire handlers** - Populate `plugin_rules` in file handlers (JS, CSS, etc.)
6. **Filtering logic** - Implement severity handling in `flush_matches()`:
   - Off → skip emission
   - Warn/Error → modify diagnostic severity via `with_severity()`
7. **Tests** - Add integration tests for both disabling and severity changes

## Full Severity Support

For warn/error severity changes (not just "off"):

1. Store plugin rule config as `FxHashMap<String, RulePlainConfiguration>` (not just disabled set)
2. In `flush_matches()`, for plugin signals:
   - If `Off` → skip emission (don't call emit_signal)
   - If `Warn` or `Error` → get diagnostic via `signal.diagnostic()`, apply `with_severity()`, emit modified diagnostic
3. The `AnalyzerDiagnostic` type supports `with_severity()` via `DiagnosticExt` trait

### Implementation Detail
In `crates/biome_analyze/src/lib.rs` around line 495:
```rust
// For plugin signals, check configured severity
if let SignalRuleKey::Plugin(plugin_name) = &entry.rule {
    if let Some(config) = self.options.configuration.plugin_rules.get(plugin_name.as_ref()) {
        match config {
            RulePlainConfiguration::Off => {
                self.signal_queue.pop();
                continue;
            }
            RulePlainConfiguration::Warn | RulePlainConfiguration::Error => {
                // Modify severity before emission
                if let Some(diag) = entry.signal.diagnostic() {
                    let severity = Severity::from(*config);
                    let modified_diag = diag.with_severity(severity);
                    // Emit modified diagnostic
                }
                self.signal_queue.pop();
                continue;
            }
            _ => {} // On/Info - use default behavior
        }
    }
}
```

## Edge Cases

- **Precedence**: Config disabling takes precedence (can't re-enable via comment)
- **Override merging**: Plugin rules merge (later overrides win for same rule name)
- **Unknown names**: Consider warning for plugin names that don't exist (follow-up)

## Detailed Implementation Notes

### Configuration Types Location
- `LinterConfiguration` is at `crates/biome_configuration/src/analyzer/linter/mod.rs:19`
- `OverrideLinterConfiguration` is at `crates/biome_configuration/src/overrides.rs:182`

### AnalyzerConfiguration Location
- `AnalyzerConfiguration` is at `crates/biome_analyze/src/options.rs:57`
- Built in file handlers like `crates/biome_service/src/file_handlers/javascript.rs:380`
- Add `.with_plugin_rules(plugin_rules)` builder method

### Filtering Location
- `flush_matches()` in `crates/biome_analyze/src/lib.rs` around line 412
- Check `SignalRuleKey::Plugin(plugin)` case (line 423)

## Verification

1. Create a test Grit plugin with a named rule
2. Configure `pluginRules: { "rule-name": "off" }` in biome.json
3. Run `cargo biome-cli-dev lint` and verify the rule is suppressed
4. Add an override for a specific path and verify path-specific suppression works
5. Run existing plugin tests: `cargo test -p biome_service plugin`
6. Run `just gen-analyzer` if needed for any generated code
</claude-plan>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.changeset/plugin-enabled-option.md:
- Around line 16-19: The "Supported severity values" list incorrectly states
that "warn" and "error" override plugin diagnostics while only "off" is
implemented; update that section to clearly state that only "off" is currently
supported (disables the plugin) and move "warn" and "error" entries into a
"Planned" or "Future" subsection (or annotate them as not yet implemented), and
adjust any wording that claims severity override works now so it instead notes
it's a planned feature and not available yet.
🧹 Nitpick comments (2)
crates/biome_plugin_loader/src/configuration.rs (2)

19-20: Type alias naming collision with crates/biome_analyze/src/options.rs.

This file defines PluginSeverityMap = FxHashMap<Box<str>, PluginSeverity>, whilst options.rs defines PluginSeverityMap = FxHashMap<Box<str>, Option<Severity>>. These are different types with the same name in different crates.

This may cause confusion. The conversion likely happens via to_diagnostic_severity(), but consider renaming one (e.g., PluginSeverityConfigMap here) or adding a doc comment clarifying the relationship.


153-165: Add validation to reject empty path strings during deserialisation.

The #[serde(default)] allows empty strings through. Whilst empty paths will fail gracefully when loading (manifest file won't be found), consider adding explicit validation to provide clearer error messages at configuration time rather than at load time.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f96af2 and b93d600.

📒 Files selected for processing (12)
  • .changeset/plugin-enabled-option.md
  • crates/biome_analyze/src/analyzer_plugin.rs
  • crates/biome_analyze/src/lib.rs
  • crates/biome_analyze/src/options.rs
  • crates/biome_plugin_loader/src/configuration.rs
  • crates/biome_service/src/file_handlers/css.rs
  • crates/biome_service/src/file_handlers/graphql.rs
  • crates/biome_service/src/file_handlers/html.rs
  • crates/biome_service/src/file_handlers/javascript.rs
  • crates/biome_service/src/file_handlers/json.rs
  • crates/biome_service/src/settings.rs
  • crates/biome_service/src/workspace.tests.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/biome_service/src/settings.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use the dbg!() macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests

Files:

  • crates/biome_service/src/file_handlers/html.rs
  • crates/biome_analyze/src/analyzer_plugin.rs
  • crates/biome_service/src/file_handlers/css.rs
  • crates/biome_analyze/src/lib.rs
  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
  • crates/biome_plugin_loader/src/configuration.rs
  • crates/biome_service/src/file_handlers/json.rs
  • crates/biome_service/src/file_handlers/javascript.rs
  • crates/biome_service/src/file_handlers/graphql.rs
crates/biome_service/src/workspace*.rs

📄 CodeRabbit inference engine (crates/biome_service/CONTRIBUTING.md)

Implement the Workspace trait in the Biome Service to manage internal state of projects, including open documents, project layout instances, and module graph instances

Files:

  • crates/biome_service/src/workspace.tests.rs
🧠 Learnings (44)
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Use `Option<_>` wrapper for rule option fields to enable proper merging of configurations

Applied to files:

  • crates/biome_service/src/file_handlers/html.rs
  • crates/biome_analyze/src/lib.rs
  • crates/biome_analyze/src/options.rs
  • crates/biome_plugin_loader/src/configuration.rs
  • crates/biome_service/src/file_handlers/json.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(rename_all = "camelCase")]` to rule option structs to match JSON configuration naming convention

Applied to files:

  • crates/biome_service/src/file_handlers/html.rs
  • crates/biome_analyze/src/lib.rs
  • crates/biome_plugin_loader/src/configuration.rs
  • crates/biome_service/src/file_handlers/json.rs
  • crates/biome_service/src/file_handlers/graphql.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(deny_unknown_fields)]` to rule option structs to enforce strict configuration validation

Applied to files:

  • crates/biome_service/src/file_handlers/html.rs
  • crates/biome_analyze/src/lib.rs
  • crates/biome_analyze/src/options.rs
  • crates/biome_plugin_loader/src/configuration.rs
  • crates/biome_service/src/file_handlers/json.rs
  • crates/biome_service/src/file_handlers/graphql.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Rule options must be defined in the `biome_rule_options` crate with a file named after the rule

Applied to files:

  • crates/biome_service/src/file_handlers/html.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use the `Semantic<T>` query type to access semantic information about bindings, references, and scope within a rule

Applied to files:

  • crates/biome_service/src/file_handlers/html.rs
  • crates/biome_analyze/src/lib.rs
  • crates/biome_service/src/file_handlers/graphql.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `action` function and add `fix_kind` metadata to the rule macro if the rule provides code actions

Applied to files:

  • crates/biome_service/src/file_handlers/html.rs
  • crates/biome_service/src/file_handlers/graphql.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `diagnostic` function to provide error messages explaining what the error is, why it is triggered, and what the user should do

Applied to files:

  • crates/biome_analyze/src/analyzer_plugin.rs
  • crates/biome_analyze/src/lib.rs
  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Implement the Diagnostic trait on types, or use the #[derive(Diagnostic)] procedural macro to implement the trait. Configure category, severity, description, message, location, and tags using the #[diagnostic] attribute

Applied to files:

  • crates/biome_analyze/src/analyzer_plugin.rs
  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use helper functions like `map`, `filter`, and `and_then` to avoid excessive nested `if let` statements

Applied to files:

  • crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `rule_category!()` macro to refer to the diagnostic category instead of dynamically parsing its string name

Applied to files:

  • crates/biome_analyze/src/analyzer_plugin.rs
  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `Markup!` macro for diagnostic messages and code action descriptions to ensure proper formatting

Applied to files:

  • crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Prefer using `Box<[_]>` over `Vec<_>` for signal collections to reduce memory usage

Applied to files:

  • crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use helper types from the biome_diagnostics::v2 module (CodeFrameAdvice, CommandAdvice, DiffAdvice, LogAdvice) or implement the Advices trait yourself for custom advice handling

Applied to files:

  • crates/biome_analyze/src/analyzer_plugin.rs
  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-12-22T09:27:13.161Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:27:13.161Z
Learning: In crates/biome_analyze/**/*analyze/src/**/*.rs, the `fix_kind` field in `declare_lint_rule!` should only be specified when the rule implements the `action` function. Rules that only emit diagnostics without providing code fixes should not include `fix_kind` in their metadata.

Applied to files:

  • crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use #[derive(Diagnostic)] on enums when every variant contains a type that is itself a diagnostic

Applied to files:

  • crates/biome_analyze/src/analyzer_plugin.rs
  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Invalid code snippets in rule documentation must emit exactly one diagnostic

Applied to files:

  • crates/biome_analyze/src/analyzer_plugin.rs
  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `run` function to return `Option<Self::State>` or `Vec<Self::State>` (as `Box<[Self::State]>`) depending on whether the rule reports one or multiple signals

Applied to files:

  • crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Implement `biome_deserialize::Merge` for rule option types to define how shared and user configurations are merged

Applied to files:

  • crates/biome_analyze/src/lib.rs
  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Deprecated rules must include a `deprecated` field in the `declare_lint_rule!` macro with an explanation of what rule to use instead

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement custom `Queryable` and `Visitor` types for rules that require deep inspection of child nodes to avoid inefficient traversals

Applied to files:

  • crates/biome_analyze/src/lib.rs
  • crates/biome_service/src/file_handlers/graphql.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `use` prefix when the rule's sole intention is to mandate a single concept

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `ctx.get_service()` to retrieve services by type when a rule requires multiple services beyond those pulled in the Query

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : When porting rules from other linters, use `sources` metadata with `RuleSource::Eslint().same()` for identical behavior or `.inspired()` for different behavior

Applied to files:

  • crates/biome_analyze/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Check if a variable is global using the semantic model before reporting diagnostics for rules that ban global functions or variables

Applied to files:

  • crates/biome_analyze/src/lib.rs
  • crates/biome_service/src/file_handlers/graphql.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Implement watcher tests for workspace methods in watcher.tests.rs and end-to-end tests in LSP tests

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/tests/specs/**/* : Create test files with `invalid` and `valid` prefixes to represent code that should and should not trigger the rule

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/Cargo.toml : Include development dependencies in `Cargo.toml` for formatter tests: `biome_formatter_test`, `biome_<language>_factory`, `biome_<language>_parser`, `biome_parser`, `biome_service`, `countme`, `iai`, `quickcheck`, `quickcheck_macros`, and `tests_macros`

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Ensure the type implementing Diagnostic derives Debug

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Build debug binaries using `cargo build --bin biome` for development and triaging

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/crates/biome_diagnostics_categories/src/categories.rs : Register all new diagnostic categories in crates/biome_diagnostics_categories/src/categories.rs

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Fields with #[advice] or #[verbose_advice] attributes must implement the Advices trait to record advices on the diagnostic

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Use the `dbg_write!` macro to debug formatter output instead of other logging methods

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Debug the WorkspaceWatcher by starting the daemon with cargo run --bin=biome -- start and running commands such as cargo run --bin=biome -- lint --use-server <path>

Applied to files:

  • crates/biome_service/src/workspace.tests.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Use `Box<[Box<str>]>` instead of `Vec<String>` for collections of strings in rule options to save memory

Applied to files:

  • crates/biome_analyze/src/options.rs
📚 Learning: 2025-12-31T15:19:03.056Z
Learnt from: Netail
Repo: biomejs/biome PR: 8631
File: crates/biome_cli/src/reporter/sarif.rs:197-218
Timestamp: 2025-12-31T15:19:03.056Z
Learning: In SARIF 2.1.0 reporter (crates/biome_cli/src/reporter/sarif.rs), when location data (source_code or span) is unavailable, omit the region field entirely using Option and #[serde(skip_serializing_if = "Option::is_none")] rather than defaulting to 0 values, as the SARIF spec states "If the region property is absent, the physicalLocation object refers to the entire artifact."

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Rule option types must derive `Deserializable`, `Serialize`, `Deserialize`, and optionally `JsonSchema` traits

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Do not attempt to 'fix' the code; if a token/node is known to be mandatory but is missing, return `None` instead

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2025-12-31T15:35:41.261Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8639
File: crates/biome_js_analyze/src/lint/nursery/no_excessive_lines_per_file.rs:101-108
Timestamp: 2025-12-31T15:35:41.261Z
Learning: In crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs, the `issue_number` field in `declare_lint_rule!` macro is optional and the vast majority of nursery rules do not need it. Do not recommend adding `issue_number` unless there's a specific reason.

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2025-12-04T13:29:49.287Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8291
File: crates/biome_html_formatter/tests/specs/prettier/vue/html-vue/elastic-header.html:10-10
Timestamp: 2025-12-04T13:29:49.287Z
Learning: Files under `crates/biome_html_formatter/tests/specs/prettier` are test fixtures synced from Prettier and should not receive detailed code quality reviews (e.g., HTTP vs HTTPS, formatting suggestions, etc.). These files are test data meant to validate formatter behavior and should be preserved as-is.

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Store type data in linear vectors instead of using recursive data structures with `Arc` for improved data locality and performance

Applied to files:

  • crates/biome_plugin_loader/src/configuration.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/language_kind.rs : Add a new language prefix to the `LANGUAGE_PREFIXES` constant in `language_kind.rs` file

Applied to files:

  • crates/biome_service/src/file_handlers/graphql.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_node_union!` macro to query multiple node types together to avoid redundant traversal passes

Applied to files:

  • crates/biome_service/src/file_handlers/graphql.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/language_kind.rs : Add a new variant to `LanguageKind` enum in `language_kind.rs` file and implement all methods for the new language variant

Applied to files:

  • crates/biome_service/src/file_handlers/graphql.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_lint_rule!` macro with a `version` field set to `next` for new rules

Applied to files:

  • crates/biome_service/src/file_handlers/graphql.rs
🧬 Code graph analysis (6)
crates/biome_service/src/file_handlers/html.rs (1)
crates/biome_service/src/configuration.rs (1)
  • to_analyzer_rules (457-475)
crates/biome_analyze/src/analyzer_plugin.rs (1)
crates/biome_plugin_loader/src/configuration.rs (2)
  • name (99-102)
  • severity (105-110)
crates/biome_service/src/file_handlers/css.rs (2)
crates/biome_js_semantic/src/semantic_model/model.rs (1)
  • global (99-101)
crates/biome_service/src/configuration.rs (1)
  • file_path (129-131)
crates/biome_analyze/src/options.rs (1)
packages/@biomejs/plugin-api/index.d.ts (1)
  • Severity (1-1)
crates/biome_service/src/file_handlers/json.rs (2)
crates/biome_js_semantic/src/semantic_model/model.rs (1)
  • global (99-101)
crates/biome_plugin_loader/src/configuration.rs (1)
  • path (91-96)
crates/biome_service/src/file_handlers/graphql.rs (1)
crates/biome_service/src/configuration.rs (1)
  • to_analyzer_rules (457-475)
🪛 LanguageTool
.changeset/plugin-enabled-option.md

[uncategorized] ~18-~18: Loose punctuation mark.
Context: ...ely (no diagnostics emitted). - "warn": Override plugin diagnostics to warning ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~19-~19: Loose punctuation mark.
Context: ...nostics to warning severity. - "error": Override plugin diagnostics to error se...

(UNLIKELY_OPENING_PUNCTUATION)

🔇 Additional comments (18)
crates/biome_service/src/file_handlers/graphql.rs (1)

174-176: Nice: per-path plugin disablement now reaches GraphQL analysis.
This looks like the right hook point (same path.as_path() used for rules + plugin severities).

crates/biome_service/src/file_handlers/html.rs (1)

203-206: LGTM: HTML analyser options now carry plugin severities.
Keeps behaviour unchanged unless a plugin is explicitly configured/disabled for the path.

crates/biome_service/src/file_handlers/json.rs (1)

232-236: Good wiring: JSON analyser now respects per-path plugin severity config.
Chaining after with_preferred_quote(...) is fine; nothing here looks order-sensitive.

crates/biome_service/src/file_handlers/css.rs (1)

237-249: CSS: per-path plugin severities plumbed through cleanly.
This should make severity: off behave as expected without touching the rest of the CSS pipeline.

crates/biome_service/src/file_handlers/javascript.rs (1)

380-387: JS/TS: nice and tidy propagation of plugin severities into analyser config.
Should enable per-path plugin disabling consistently across lint / actions / fix-all.

crates/biome_analyze/src/analyzer_plugin.rs (1)

106-138: LGTM! Clean implementation of severity overrides.

The filter_map approach correctly handles both disabling plugins (via None) and overriding severity. The logic follows the expected pattern from PluginSeverityMap.

One minor observation: the SignalEntry construction is duplicated between lines 120-126 and 131-137. If this grows, consider extracting a helper, but it's fine for now.

crates/biome_analyze/src/lib.rs (1)

41-43: LGTM!

Straightforward addition of PluginSeverityMap to the public API surface, consistent with existing re-export patterns.

crates/biome_plugin_loader/src/configuration.rs (4)

27-33: LGTM!

Clean builder for the severity map from plugin configurations.


89-125: Well-structured API with good documentation.

The helper methods (path, name, severity, has_explicit_severity, is_enabled) provide a clean interface. The name() fallback to the full path when file_stem() returns None is sensible.


141-151: LGTM!

The to_diagnostic_severity method correctly maps Off to None for skipping, and the other variants to their diagnostic equivalents.


237-290: Comprehensive test coverage.

Tests cover path normalisation with options, name extraction from various path formats, and all severity/enabled combinations. Good work!

crates/biome_analyze/src/options.rs (3)

10-12: LGTM!

The PluginSeverityMap type with Option<Severity> values correctly represents the three states: no override, disabled (None), or severity override (Some).


85-89: LGTM!

The field is appropriately placed and documented.


212-222: Excellent documentation on the Option<Option<Severity>> semantics.

The triple-state return value (no config / off / override) is well-explained. This makes the API much easier to use correctly.

crates/biome_service/src/workspace.tests.rs (4)

14-14: LGTM!

Import updated correctly to include the new types.


678-753: Good test for disabling plugins via options.

Covers the basic case of globally disabling a plugin and verifying no diagnostics are emitted.


755-875: Excellent test for override precedence.

This test validates that:

  1. Plugin enabled globally produces diagnostics for a.ts
  2. Plugin disabled via path override produces no diagnostics for scripts/b.ts

Good coverage of the override merging behaviour.


877-964: Good test for severity override to warning.

Verifies that configuring PluginSeverity::Warn correctly changes the diagnostic severity from Error to Warning. The assertion on line 958-962 explicitly checks the severity value, which is thorough.

Disabled plugins (severity: off) are now skipped during plugin loading.
This prevents errors when a plugin file doesn't exist but is configured
as disabled.

Added test to verify disabled plugins with missing files don't error.

Claude-Generated-By: Claude Code (cli/claude-opus-4-5=100%)
Claude-Steers: 1
Claude-Permission-Prompts: 0
Claude-Escapes: 0
Claude-Plan:
<claude-plan>
# Plan: Plugin Rule Configuration in Overrides

## Goal
Add support for configuring individual plugin rules (enable/disable/severity) via configuration, including in overrides.

**Target syntax:**
```json
{
  "linter": {
    "pluginRules": {
      "no-process-cwd": "off",
      "my-rule": "warn"
    }
  },
  "overrides": [{
    "includes": ["scripts/**"],
    "linter": {
      "pluginRules": { "no-process-cwd": "off" }
    }
  }]
}
```

## Background

- Plugin rules are identified by `SignalRuleKey::Plugin(name)` where name comes from the Grit pattern's `name` field
- Suppression already works via comments (`// biome-ignore lint/plugin/ruleName`)
- `TopLevelSuppression.plugins` tracks suppressed plugin names
- No configuration-based mechanism exists yet

## Implementation Approach

Use the existing suppression mechanism path (not `RuleFilter`) because:
- Plugin names are dynamic strings, not `'static` references like built-in rules
- Plugins already have their own suppression path (`suppressed_plugin()`)
- Minimal changes to core types

## Files to Modify

### 1. Configuration Schema

**`crates/biome_configuration/src/analyzer/linter/mod.rs`**
- Add `PluginRules` type: `FxHashMap<String, RulePlainConfiguration>`
- Add `plugin_rules: Option<PluginRules>` field to `LinterConfiguration`

**`crates/biome_configuration/src/overrides.rs`**
- Add `plugin_rules: Option<PluginRules>` to `OverrideLinterConfiguration`

### 2. Settings Layer

**`crates/biome_service/src/settings.rs`**
- Add `plugin_rules: Option<PluginRules>` to `LinterSettings`
- Add to `OverrideLinterSettings`
- Update `to_linter_settings()` to pass through plugin_rules
- Add `as_plugin_rules(&self, path: &Utf8Path) -> PluginRules` method to merge base + overrides

### 3. Analyzer Integration

**`crates/biome_analyze/src/options.rs`**
- Add `plugin_rules: FxHashMap<String, RulePlainConfiguration>` to `AnalyzerConfiguration`
- Add builder method `with_plugin_rules()`

**`crates/biome_analyze/src/lib.rs`**
- Modify `flush_matches()` around line 423 to check plugin rule configuration
- Handle Off/Warn/Error severities appropriately

### 4. Wire Configuration to Analyzer

**`crates/biome_service/src/file_handlers/javascript.rs`** (and other handlers)
- When building `AnalyzerConfiguration`, populate `plugin_rules` from settings

## Implementation Steps

1. **Add configuration types** - Create `PluginRules` type (`FxHashMap<String, RulePlainConfiguration>`) and add to `LinterConfiguration`
2. **Add to overrides** - Add field to `OverrideLinterConfiguration`
3. **Settings layer** - Add field to `LinterSettings`, implement merging via `as_plugin_rules(path)`
4. **Analyzer options** - Add `plugin_rules` field to `AnalyzerConfiguration`
5. **Wire handlers** - Populate `plugin_rules` in file handlers (JS, CSS, etc.)
6. **Filtering logic** - Implement severity handling in `flush_matches()`:
   - Off → skip emission
   - Warn/Error → modify diagnostic severity via `with_severity()`
7. **Tests** - Add integration tests for both disabling and severity changes

## Full Severity Support

For warn/error severity changes (not just "off"):

1. Store plugin rule config as `FxHashMap<String, RulePlainConfiguration>` (not just disabled set)
2. In `flush_matches()`, for plugin signals:
   - If `Off` → skip emission (don't call emit_signal)
   - If `Warn` or `Error` → get diagnostic via `signal.diagnostic()`, apply `with_severity()`, emit modified diagnostic
3. The `AnalyzerDiagnostic` type supports `with_severity()` via `DiagnosticExt` trait

### Implementation Detail
In `crates/biome_analyze/src/lib.rs` around line 495:
```rust
// For plugin signals, check configured severity
if let SignalRuleKey::Plugin(plugin_name) = &entry.rule {
    if let Some(config) = self.options.configuration.plugin_rules.get(plugin_name.as_ref()) {
        match config {
            RulePlainConfiguration::Off => {
                self.signal_queue.pop();
                continue;
            }
            RulePlainConfiguration::Warn | RulePlainConfiguration::Error => {
                // Modify severity before emission
                if let Some(diag) = entry.signal.diagnostic() {
                    let severity = Severity::from(*config);
                    let modified_diag = diag.with_severity(severity);
                    // Emit modified diagnostic
                }
                self.signal_queue.pop();
                continue;
            }
            _ => {} // On/Info - use default behavior
        }
    }
}
```

## Edge Cases

- **Precedence**: Config disabling takes precedence (can't re-enable via comment)
- **Override merging**: Plugin rules merge (later overrides win for same rule name)
- **Unknown names**: Consider warning for plugin names that don't exist (follow-up)

## Detailed Implementation Notes

### Configuration Types Location
- `LinterConfiguration` is at `crates/biome_configuration/src/analyzer/linter/mod.rs:19`
- `OverrideLinterConfiguration` is at `crates/biome_configuration/src/overrides.rs:182`

### AnalyzerConfiguration Location
- `AnalyzerConfiguration` is at `crates/biome_analyze/src/options.rs:57`
- Built in file handlers like `crates/biome_service/src/file_handlers/javascript.rs:380`
- Add `.with_plugin_rules(plugin_rules)` builder method

### Filtering Location
- `flush_matches()` in `crates/biome_analyze/src/lib.rs` around line 412
- Check `SignalRuleKey::Plugin(plugin)` case (line 423)

## Verification

1. Create a test Grit plugin with a named rule
2. Configure `pluginRules: { "rule-name": "off" }` in biome.json
3. Run `cargo biome-cli-dev lint` and verify the rule is suppressed
4. Add an override for a specific path and verify path-specific suppression works
5. Run existing plugin tests: `cargo test -p biome_service plugin`
6. Run `just gen-analyzer` if needed for any generated code
</claude-plan>
@ematipico
Copy link
Member

Why wasn't the info severity implemented?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Linter Area: linter A-Project Area: project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants