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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .changeset/plugin-enabled-option.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
"@biomejs/biome": minor
---

Add `severity` option to plugin configuration. Plugins can now be configured using 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 (no diagnostics emitted).
- `"warn"`: Override plugin diagnostics to warning severity.
- `"error"`: Override plugin diagnostics to error severity (default).

This allows configuring plugin behavior per-path via overrides:

```json
{
"plugins": ["./my-plugin.grit"],
"overrides": [{
"includes": ["scripts/**"],
"plugins": [{ "path": "./my-plugin.grit", "severity": "off" }]
}]
}
```
25 changes: 22 additions & 3 deletions crates/biome_analyze/src/analyzer_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,38 @@ where
.plugin
.evaluate(node.clone().into(), ctx.options.file_path.clone())
.into_iter()
.map(|diagnostic| {
.filter_map(|diagnostic| {
let name = diagnostic
.subcategory
.clone()
.unwrap_or_else(|| "anonymous".into());

SignalEntry {
// Check if there's a severity override for this plugin
if let Some(severity_override) = ctx.options.plugin_severity(&name) {
match severity_override {
// Plugin is disabled - skip this diagnostic
None => return None,
// Override the severity
Some(severity) => {
let diagnostic = diagnostic.with_severity(severity);
return Some(SignalEntry {
text_range: diagnostic.span().unwrap_or_default(),
signal: Box::new(DiagnosticSignal::new(move || diagnostic.clone())),
rule: SignalRuleKey::Plugin(name.into()),
category: RuleCategory::Lint,
instances: Default::default(),
});
}
}
}

Some(SignalEntry {
text_range: diagnostic.span().unwrap_or_default(),
signal: Box::new(DiagnosticSignal::new(move || diagnostic.clone())),
rule: SignalRuleKey::Plugin(name.into()),
category: RuleCategory::Lint,
instances: Default::default(),
}
})
});

ctx.signal_queue.extend(signals);
Expand Down
4 changes: 3 additions & 1 deletion crates/biome_analyze/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ pub use crate::categories::{
pub use crate::diagnostics::{AnalyzerDiagnostic, AnalyzerSuppressionDiagnostic, RuleError};
use crate::matcher::SignalRuleKey;
pub use crate::matcher::{InspectMatcher, MatchQueryParams, QueryMatcher, RuleKey, SignalEntry};
pub use crate::options::{AnalyzerConfiguration, AnalyzerOptions, AnalyzerRules};
pub use crate::options::{
AnalyzerConfiguration, AnalyzerOptions, AnalyzerRules, PluginSeverityMap,
};
pub use crate::query::{AddVisitor, QueryKey, QueryMatch, Queryable};
pub use crate::registry::{
LanguageRoot, MetadataRegistry, Phase, Phases, RegistryRuleMetadata, RegistryVisitor,
Expand Down
26 changes: 26 additions & 0 deletions crates/biome_analyze/src/options.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use biome_diagnostics::Severity;
use camino::Utf8PathBuf;
use rustc_hash::FxHashMap;

Expand All @@ -6,6 +7,10 @@ use std::any::{Any, TypeId};
use std::borrow::Cow;
use std::sync::Arc;

/// Map from plugin name to severity configuration.
/// None means "off" (skip the diagnostic), Some(severity) means override to that severity.
pub type PluginSeverityMap = FxHashMap<Box<str>, Option<Severity>>;

/// A convenient new type data structure to store the options that belong to a rule
#[derive(Debug)]
pub struct RuleOptions(TypeId, Box<dyn Any>, Option<FixKind>);
Expand Down Expand Up @@ -77,6 +82,11 @@ pub struct AnalyzerConfiguration {

/// Whether the CSS files contain CSS Modules
css_modules: bool,

/// Severity configuration for plugins.
/// Keys are plugin names (derived from file stems), values are severity overrides.
/// None means "off" (skip diagnostics), Some(severity) means override to that level.
pub plugin_severities: PluginSeverityMap,
}

impl AnalyzerConfiguration {
Expand Down Expand Up @@ -117,6 +127,11 @@ impl AnalyzerConfiguration {
self.css_modules = css_modules;
self
}

pub fn with_plugin_severities(mut self, plugin_severities: PluginSeverityMap) -> Self {
self.plugin_severities = plugin_severities;
self
}
}

/// A set of information useful to the analyzer infrastructure
Expand Down Expand Up @@ -194,6 +209,17 @@ impl AnalyzerOptions {
pub fn css_modules(&self) -> bool {
self.configuration.css_modules
}

/// Get the configured severity for a plugin.
/// Returns None if no configuration exists for this plugin.
/// Returns Some(None) if the plugin is configured as "off".
/// Returns Some(Some(severity)) if a severity override is configured.
pub fn plugin_severity(&self, plugin_name: &str) -> Option<Option<Severity>> {
self.configuration
.plugin_severities
.get(plugin_name)
.copied()
}
}

#[derive(Clone, Copy, Debug, Default)]
Expand Down
Loading