-
-
Notifications
You must be signed in to change notification settings - Fork 696
refactor(analyze): integrate plugin as a syntax visitor #7369
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(analyze): integrate plugin as a syntax visitor #7369
Conversation
🦋 Changeset detectedLatest commit: 2d9f693 The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
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 |
WalkthroughAnalyzer plugins are now language-aware and operate per erased syntax node ( Possibly related PRs
Suggested reviewers
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
⏰ 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). (10)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
CodSpeed Performance ReportMerging #7369 will not alter performanceComparing Summary
|
f28badf
to
ee27873
Compare
ee27873
to
15d3550
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/biome_analyze/src/matcher.rs (1)
148-159
: Handle thePlugin
variant in suppressions and reporting
- In crates/biome_analyze/src/lib.rs around line 410, extend the
match &entry.rule
for suppressions to include aSignalRuleKey::Plugin(id) => …
branch (or wildcard) so plugin-emitted signals aren’t silently ignored.- In the reporting logic around line 460, similarly handle
SignalRuleKey::Plugin(id)
—e.g. format or filter by the plugin key—rather than only matching onRule(_)
.
🧹 Nitpick comments (10)
crates/biome_grit_patterns/src/grit_query.rs (1)
56-58
: Guard the “compiled-for-this-language” invariant
from_node
compiles patterns against a specificlang
, whileexecute
readsself.language
. Because the field is nowpub
, external mutation after construction can desynchronise the compiled pattern from the execution context. Consider keeping the field private and exposing a getter to make it read-only.Apply within this hunk:
- /// Target language for the query. - pub language: GritTargetLanguage, + /// Target language for the query. Set at compile time; do not mutate after construction. + language: GritTargetLanguage,Then add an accessor within the existing
impl GritQuery
:impl GritQuery { /// Returns the target language used during compilation. pub fn language(&self) -> &GritTargetLanguage { &self.language } }crates/biome_analyze/src/matcher.rs (1)
141-146
: Prefer Arc for plugin keys to avoid repeated allocations.Plugin signals will likely reuse the same plugin id many times. Arc reduces cloning churn versus Box.
Apply:
-#[derive(Clone, Debug)] -pub enum SignalRuleKey { - Rule(RuleKey), - Plugin(Box<str>), -} +#[derive(Clone, Debug)] +pub enum SignalRuleKey { + Rule(RuleKey), + // Shared across many signals from the same plugin + Plugin(std::sync::Arc<str>), +}Optionally, add Display for nicer logging:
impl core::fmt::Display for SignalRuleKey { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { SignalRuleKey::Rule(k) => k.fmt(f), SignalRuleKey::Plugin(id) => f.write_str(id), } } }crates/biome_js_analyze/src/lib.rs (1)
144-155
: Shrink the unsafe scope and keep it surgical.Move the language check outside the unsafe block so only new_unchecked is unsafe. Same effect, less spooky action at a distance.
Apply:
- for plugin in plugins { - // SAFETY: The plugin target language is correctly checked here. - unsafe { - if plugin.language() == PluginTargetLanguage::JavaScript { - analyzer.add_visitor( - Phases::Syntax, - Box::new(PluginVisitor::new_unchecked(plugin.clone())), - ) - } - } - } + for plugin in plugins { + if plugin.language() == PluginTargetLanguage::JavaScript { + // SAFETY: The plugin target language was checked above. + let visitor = unsafe { PluginVisitor::new_unchecked(plugin.clone()) }; + analyzer.add_visitor(Phases::Syntax, Box::new(visitor)); + } + }Minor thought: plugin visitors are appended after built-in visitors. That’s fine given heap-ordered emission, but shout if you want a stable “plugins-first/last” policy and we can wire it explicitly.
crates/biome_css_analyze/src/lib.rs (1)
118-129
: Narrow the unsafe scope to thenew_unchecked
call.for plugin in plugins { - // SAFETY: The plugin target language is correctly checked here. - unsafe { - if plugin.language() == PluginTargetLanguage::Css { - analyzer.add_visitor( - Phases::Syntax, - Box::new(PluginVisitor::new_unchecked(plugin.clone())), - ) - } - } + if plugin.language() == PluginTargetLanguage::Css { + // SAFETY: The plugin target language is correctly checked here. + let visitor = unsafe { PluginVisitor::new_unchecked(plugin.clone()) }; + analyzer.add_visitor(Phases::Syntax, Box::new(visitor)); + } }crates/biome_rowan/src/syntax/node.rs (2)
1210-1214
: Fix doc reference to the erased node type.
The comment mentionsErasedSyntaxNode
, but the type isAnySyntaxNode
.-/// Marker trait to prevent unrelated types to be contained in the [`crate::ErasedSyntaxNode`] struct. +/// Marker trait restricting which types can be stored inside [`AnySyntaxNode`].
1215-1234
: Stronger type safety: store dyn AsSyntaxNode instead of dyn Any.
This enforces at the type level that only syntax nodes are boxed (aligns with the doc) while preserving the same downcast ergonomics.-#[derive(Debug)] -pub struct AnySyntaxNode { - raw: Box<dyn Any>, -} +#[derive(Debug)] +pub struct AnySyntaxNode { + raw: Box<dyn AsSyntaxNode>, +} @@ impl AnySyntaxNode { #[inline] pub fn downcast_ref<T: AsSyntaxNode>(&self) -> Option<&T> { - self.raw.downcast_ref() + // AsSyntaxNode: Any, so we can downcast via Any + (self.raw.as_ref() as &dyn Any).downcast_ref() } } @@ impl<L: Language + 'static> From<SyntaxNode<L>> for AnySyntaxNode { fn from(value: SyntaxNode<L>) -> Self { - Self { - raw: Box::new(value), - } + Self { raw: Box::new(value) } } }If
#[derive(Debug)]
ever complains about the trait object, we can add a tiny manualDebug
impl that prints the inner type name. Happy to provide it.crates/biome_analyze/src/analyzer_plugin.rs (1)
47-55
: Provide a safe constructor alongsidenew_unchecked
The unsafe ctor is easy to misuse. Offer a safe
new(plugin) -> Option<Self>
(or Result) that checksplugin.language()
matchesL
to prevent accidental cross-language registration.pub unsafe fn new_unchecked(plugin: Arc<Box<dyn AnalyzerPlugin>>) -> Self { let query = plugin.query().into_iter().map(L::Kind::from_raw).collect(); Self { query, plugin, skip_subtree: None, } } + +pub fn new(plugin: Arc<Box<dyn AnalyzerPlugin>>, expected: PluginTargetLanguage) -> Option<Self> { + if plugin.language() != expected { + return None; + } + // SAFETY: Language checked above. + Some(unsafe { Self::new_unchecked(plugin) }) +}crates/biome_analyze/src/suppressions.rs (3)
191-197
: New range-suppression plugin fields look goodThe added fields model plugin-specific range suppressions cleanly. Minor nit: prefer initialising booleans explicitly to
false
rather thanDefault::default()
for readability.- suppress_all_plugins: Default::default(), + suppress_all_plugins: false,Also applies to: 208-211
620-633
: Consider reporting “already suppressed” for plugin suppressions too
already_suppressed(...)
only checks rule filters; it won’t attribute a plugin line/range suppression as redundant when a top-level plugin suppression already applies. For parity with rules (nicer UX), extend this to consult plugin suppressions as well.Here’s a minimal change:
- fn already_suppressed( - &self, - filter: Option<&RuleFilter>, - range: &TextRange, - ) -> Option<TextRange> { - filter.and_then(|filter| { - self.top_level_suppression - .has_filter(filter) - .then_some(self.top_level_suppression.comment_range) - .or(self - .range_suppressions - .matches_filter_in_range(filter, range)) - }) - } + fn already_suppressed( + &self, + filter: Option<&RuleFilter>, + range: &TextRange, + plugin_name: Option<&str>, + ) -> Option<TextRange> { + // Rule-based overshadowing + if let Some(filter) = filter { + if self.top_level_suppression.has_filter(filter) { + return Some(self.top_level_suppression.comment_range); + } + if let Some(r) = self.range_suppressions.matches_filter_in_range(filter, range) { + return Some(r); + } + } + // Plugin-based overshadowing + if let Some(name) = plugin_name { + if self.top_level_suppression.suppressed_plugin(name) { + return Some(self.top_level_suppression.comment_range); + } + if let Some(r) = self.range_suppressions.matches_plugin_in_range(name, range) { + return Some(r); + } + } + None + }Add this helper to
RangeSuppressions
:+ pub(crate) fn matches_plugin_in_range( + &self, + plugin: &str, + position: &TextRange, + ) -> Option<TextRange> { + for s in self.suppressions.iter().rev() { + if s.suppression_range.contains_range(*position) + && (s.suppress_all_plugins || s.suppressed_plugins.contains(plugin)) + { + return Some(s.suppression_range); + } + } + None + }And pass
plugin_name.as_deref()
from callers where you computealready_suppressed
.Happy to wire this across the three call sites if you’d like a patch.
703-712
: Docs: suppression example typoThe example reads “// lint/biome-ignore plugin/my-plugin”. Should be “// biome-ignore lint/plugin/my-plugin”.
- /// A suppression disabling a plugin eg. `// lint/biome-ignore plugin/my-plugin` + /// A suppression disabling a plugin, e.g. `// biome-ignore lint/plugin/my-plugin`
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (5)
Cargo.lock
is excluded by!**/*.lock
and included by**
crates/biome_js_analyze/tests/plugin/preferObjectSpreadSuppression.grit.snap
is excluded by!**/*.snap
and included by**
crates/biome_js_analyze/tests/plugin/preferObjectSpreadSuppressionAll.grit.snap
is excluded by!**/*.snap
and included by**
crates/biome_service/src/snapshots/biome_service__workspace__tests__plugins_are_loaded_and_used_during_analysis.snap
is excluded by!**/*.snap
and included by**
crates/biome_service/src/snapshots/biome_service__workspace__tests__plugins_may_use_invalid_span.snap
is excluded by!**/*.snap
and included by**
📒 Files selected for processing (14)
crates/biome_analyze/src/analyzer_plugin.rs
(2 hunks)crates/biome_analyze/src/lib.rs
(5 hunks)crates/biome_analyze/src/matcher.rs
(3 hunks)crates/biome_analyze/src/registry.rs
(2 hunks)crates/biome_analyze/src/suppressions.rs
(6 hunks)crates/biome_css_analyze/src/lib.rs
(2 hunks)crates/biome_grit_patterns/src/grit_query.rs
(1 hunks)crates/biome_js_analyze/src/lib.rs
(2 hunks)crates/biome_plugin_loader/Cargo.toml
(1 hunks)crates/biome_plugin_loader/src/analyzer_grit_plugin.rs
(2 hunks)crates/biome_plugin_loader/src/analyzer_js_plugin.rs
(4 hunks)crates/biome_rowan/src/lib.rs
(1 hunks)crates/biome_rowan/src/syntax.rs
(1 hunks)crates/biome_rowan/src/syntax/node.rs
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{rs,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Format Rust and TOML files before committing (use
just f
/just format
).
Files:
crates/biome_js_analyze/src/lib.rs
crates/biome_rowan/src/lib.rs
crates/biome_rowan/src/syntax.rs
crates/biome_plugin_loader/Cargo.toml
crates/biome_grit_patterns/src/grit_query.rs
crates/biome_analyze/src/registry.rs
crates/biome_plugin_loader/src/analyzer_grit_plugin.rs
crates/biome_rowan/src/syntax/node.rs
crates/biome_css_analyze/src/lib.rs
crates/biome_plugin_loader/src/analyzer_js_plugin.rs
crates/biome_analyze/src/analyzer_plugin.rs
crates/biome_analyze/src/matcher.rs
crates/biome_analyze/src/lib.rs
crates/biome_analyze/src/suppressions.rs
crates/biome_*_{syntax,parser,formatter,analyze,factory,semantic}/**
📄 CodeRabbit inference engine (CLAUDE.md)
Maintain the per-language crate structure: biome_{lang}_{syntax,parser,formatter,analyze,factory,semantic}
Files:
crates/biome_js_analyze/src/lib.rs
crates/biome_css_analyze/src/lib.rs
crates/biome_*/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place core crates under /crates/biome_*/
Files:
crates/biome_js_analyze/src/lib.rs
crates/biome_rowan/src/lib.rs
crates/biome_rowan/src/syntax.rs
crates/biome_plugin_loader/Cargo.toml
crates/biome_grit_patterns/src/grit_query.rs
crates/biome_analyze/src/registry.rs
crates/biome_plugin_loader/src/analyzer_grit_plugin.rs
crates/biome_rowan/src/syntax/node.rs
crates/biome_css_analyze/src/lib.rs
crates/biome_plugin_loader/src/analyzer_js_plugin.rs
crates/biome_analyze/src/analyzer_plugin.rs
crates/biome_analyze/src/matcher.rs
crates/biome_analyze/src/lib.rs
crates/biome_analyze/src/suppressions.rs
crates/**/Cargo.toml
📄 CodeRabbit inference engine (CONTRIBUTING.md)
crates/**/Cargo.toml
: In internal crates, useworkspace = true
for internal dependencies.
Use path dependencies for dev-dependencies in internal crates.
Files:
crates/biome_plugin_loader/Cargo.toml
{Cargo.toml,crates/**/Cargo.toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Keep the version field consistent across all crates during release.
Files:
crates/biome_plugin_loader/Cargo.toml
🧠 Learnings (20)
📚 Learning: 2025-08-17T08:56:30.831Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:56:30.831Z
Learning: Applies to crates/biome_analyze/crates/biome_js_analyze/lib/src/lint/nursery/*.rs : For new JavaScript lint rules generated by `just new-js-lintrule`, implement the rule in the generated file under `biome_js_analyze/lib/src/lint/nursery/`
Applied to files:
crates/biome_js_analyze/src/lib.rs
crates/biome_plugin_loader/src/analyzer_js_plugin.rs
📚 Learning: 2025-08-17T08:55:30.118Z
Learnt from: CR
PR: biomejs/biome#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-17T08:55:30.118Z
Learning: Applies to crates/biome_*_{syntax,parser,formatter,analyze,factory,semantic}/** : Maintain the per-language crate structure: biome_{lang}_{syntax,parser,formatter,analyze,factory,semantic}
Applied to files:
crates/biome_js_analyze/src/lib.rs
crates/biome_plugin_loader/Cargo.toml
crates/biome_css_analyze/src/lib.rs
📚 Learning: 2025-08-11T11:50:12.090Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:50:12.090Z
Learning: Applies to crates/biome_js_type_info/src/**/*.rs : Represent links between types using TypeReference (not Arc) to avoid cross-module retention and recursive structures; store type data in linear vectors
Applied to files:
crates/biome_js_analyze/src/lib.rs
📚 Learning: 2025-08-17T08:57:34.751Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:57:34.751Z
Learning: Applies to crates/biome_parser/xtask/codegen/*.ungram : Union node names must start with Any* (e.g., AnyHtmlAttribute)
Applied to files:
crates/biome_rowan/src/syntax.rs
📚 Learning: 2025-08-11T11:48:52.001Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:52.001Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Use the generic Format trait and FormatNode for AST nodes when implementing the formatter
Applied to files:
crates/biome_rowan/src/syntax.rs
📚 Learning: 2025-08-11T11:48:52.001Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:52.001Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : When a token is mandatory and present in the AST, use the AST-provided token (e.g., node.l_paren_token().format()) instead of hardcoded tokens
Applied to files:
crates/biome_rowan/src/syntax.rs
📚 Learning: 2025-08-11T11:48:52.001Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:52.001Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Import the FormatNode trait and implement it for your Node
Applied to files:
crates/biome_rowan/src/syntax.rs
📚 Learning: 2025-08-11T11:48:52.001Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:52.001Z
Learning: Applies to crates/biome_js_formatter/**/Cargo.toml : Add biome_js_formatter as a path dependency in Cargo.toml: biome_js_formatter = { version = "0.0.1", path = "../biome_js_formatter" }
Applied to files:
crates/biome_plugin_loader/Cargo.toml
📚 Learning: 2025-08-11T11:48:27.774Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:27.774Z
Learning: Applies to crates/biome_formatter/biome_html_formatter/Cargo.toml : Add the specified dev-dependencies (biome_formatter_test, biome_html_factory, biome_html_parser, biome_parser, biome_service, countme with feature enable, iai 0.1.1, quickcheck, quickcheck_macros, tests_macros) to Cargo.toml under [dev-dependencies]
Applied to files:
crates/biome_plugin_loader/Cargo.toml
📚 Learning: 2025-08-11T11:40:38.097Z
Learnt from: CR
PR: biomejs/biome#0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:40:38.097Z
Learning: Applies to crates/**/Cargo.toml : In internal crates, use `workspace = true` for internal dependencies.
Applied to files:
crates/biome_plugin_loader/Cargo.toml
📚 Learning: 2025-08-17T08:57:34.751Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:57:34.751Z
Learning: Applies to crates/biome_parser/crates/biome_*_syntax/** : Create a new crate named biome_<language>_syntax under crates/
Applied to files:
crates/biome_plugin_loader/Cargo.toml
📚 Learning: 2025-08-11T11:40:38.097Z
Learnt from: CR
PR: biomejs/biome#0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:40:38.097Z
Learning: Applies to Cargo.toml : Centralize shared dependencies in the root Cargo.toml using workspace dependencies.
Applied to files:
crates/biome_plugin_loader/Cargo.toml
📚 Learning: 2025-08-11T11:53:15.299Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:53:15.299Z
Learning: Applies to crates/biome_service/src/workspace.rs : Implement the Workspace trait in src/workspace.rs
Applied to files:
crates/biome_plugin_loader/Cargo.toml
📚 Learning: 2025-08-17T08:56:30.831Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:56:30.831Z
Learning: Applies to crates/biome_analyze/crates/**/lib/src/**/nursery/**/*.rs : Use the local `rule_category!()` macro in diagnostics for the rule’s category, not string-parsed categories
Applied to files:
crates/biome_plugin_loader/src/analyzer_grit_plugin.rs
crates/biome_analyze/src/analyzer_plugin.rs
crates/biome_analyze/src/lib.rs
📚 Learning: 2025-08-11T11:48:27.774Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:27.774Z
Learning: Applies to crates/biome_formatter/biome_html_formatter/src/lib.rs : Place the plumbing traits and impls (AsFormat, IntoFormat, FormattedIterExt, and their Iterator adapters) in the biome_html_formatter crate’s lib.rs
Applied to files:
crates/biome_rowan/src/syntax/node.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Specify category and severity using #[diagnostic(...)] on the type or derive them from fields
Applied to files:
crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Types implementing Diagnostic must also implement Debug (e.g., use #[derive(Debug, Diagnostic)])
Applied to files:
crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : #[derive(Diagnostic)] can be used on enums only if every variant contains a diagnostic type
Applied to files:
crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2025-08-17T08:56:30.831Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:56:30.831Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Define per-rule options in the `biome_rule_options` crate under `lib/`, with serde- and schemars-compatible derives and `#[serde(rename_all = "camelCase", deny_unknown_fields, default)]`
Applied to files:
crates/biome_analyze/src/matcher.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/crates/biome_diagnostics_categories/src/categories.rs : When declaring a new diagnostic category, register it in crates/biome_diagnostics_categories/src/categories.rs
Applied to files:
crates/biome_analyze/src/lib.rs
🧬 Code graph analysis (8)
crates/biome_js_analyze/src/lib.rs (1)
crates/biome_analyze/src/analyzer_plugin.rs (1)
new_unchecked
(47-55)
crates/biome_analyze/src/registry.rs (1)
crates/biome_analyze/src/matcher.rs (1)
rule
(113-115)
crates/biome_plugin_loader/src/analyzer_grit_plugin.rs (3)
crates/biome_analyze/src/analyzer_plugin.rs (3)
language
(19-19)query
(21-21)evaluate
(23-23)crates/biome_plugin_loader/src/analyzer_js_plugin.rs (3)
language
(76-78)query
(80-85)evaluate
(87-122)crates/biome_grit_patterns/src/grit_context.rs (2)
language
(127-129)parse
(362-372)
crates/biome_rowan/src/syntax/node.rs (2)
crates/biome_analyze/src/registry.rs (2)
TypeId
(179-179)TypeId
(233-233)crates/biome_analyze/src/matcher.rs (1)
downcast_ref
(58-60)
crates/biome_css_analyze/src/lib.rs (1)
crates/biome_analyze/src/analyzer_plugin.rs (1)
new_unchecked
(47-55)
crates/biome_plugin_loader/src/analyzer_js_plugin.rs (2)
crates/biome_analyze/src/analyzer_plugin.rs (3)
language
(19-19)query
(21-21)evaluate
(23-23)crates/biome_plugin_loader/src/analyzer_grit_plugin.rs (3)
language
(46-51)query
(53-63)evaluate
(65-120)
crates/biome_analyze/src/analyzer_plugin.rs (3)
crates/biome_plugin_loader/src/analyzer_js_plugin.rs (4)
fmt
(52-56)language
(76-78)query
(80-85)evaluate
(87-122)crates/biome_rowan/src/syntax/node.rs (10)
fmt
(778-811)fmt
(815-817)fmt
(917-919)kind
(67-69)kind
(1048-1054)kind
(1125-1125)kind
(1129-1131)kind
(1135-1137)kind
(1184-1186)new
(1152-1154)crates/biome_plugin_loader/src/analyzer_grit_plugin.rs (6)
language
(46-51)query
(53-63)evaluate
(65-120)node
(69-70)node
(72-73)None
(103-103)
crates/biome_analyze/src/matcher.rs (2)
crates/biome_analyze/src/registry.rs (3)
RuleKey
(441-441)new
(298-300)new
(382-455)crates/biome_analyze/src/context.rs (1)
RuleKey
(42-42)
⏰ 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). (25)
- GitHub Check: Test Node.js API
- GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
- GitHub Check: Documentation
- GitHub Check: Test (depot-ubuntu-24.04-arm-16)
- GitHub Check: Lint project (depot-windows-2022)
- GitHub Check: Check Dependencies
- GitHub Check: Test (depot-windows-2022-16)
- GitHub Check: Bench (biome_configuration)
- GitHub Check: Bench (biome_json_analyze)
- GitHub Check: Bench (biome_html_formatter)
- GitHub Check: Bench (biome_graphql_formatter)
- GitHub Check: Bench (biome_package)
- GitHub Check: Bench (biome_css_parser)
- GitHub Check: Bench (biome_html_parser)
- GitHub Check: Bench (biome_module_graph)
- GitHub Check: Bench (biome_graphql_parser)
- GitHub Check: Parser conformance
- GitHub Check: Bench (biome_css_formatter)
- GitHub Check: Bench (biome_css_analyze)
- GitHub Check: Bench (biome_json_formatter)
- GitHub Check: Bench (biome_js_parser)
- GitHub Check: Bench (biome_json_parser)
- GitHub Check: Bench (biome_js_formatter)
- GitHub Check: Bench (biome_js_analyze)
- GitHub Check: autofix
🔇 Additional comments (26)
crates/biome_grit_patterns/src/grit_query.rs (2)
56-58
: LGTM: exposing language for routing fits the new visitor modelMaking
language
readable from outside will simplify plugin wiring. Nice one.
56-58
: No external writes toGritQuery.language
detected. Only occurrence of.language =
is in theRule::language
builder incrates/biome_analyze/src/rule.rs
, not onGritQuery
, and no struct literals setlanguage
elsewhere.crates/biome_rowan/src/syntax.rs (1)
10-13
: LGTM: re-exporting AnySyntaxNode.Clean public surfacing; no behavioural changes. Ship it.
crates/biome_rowan/src/lib.rs (1)
46-52
: LGTM: public API now exposes AnySyntaxNode.Consistent with the syntax module export; minimal risk.
crates/biome_analyze/src/matcher.rs (2)
214-218
: Tests import update: all good.Importing SignalRuleKey into tests aligns with the new API.
249-255
: Test signal construction updated correctly.Wrapping the RuleKey in SignalRuleKey::Rule is spot on.
crates/biome_js_analyze/src/lib.rs (1)
8-10
: LGTM: imports for PluginTargetLanguage and PluginVisitor.Matches the new analyser plugin API surface.
crates/biome_css_analyze/src/lib.rs (1)
17-19
: LGTM: import wiring matches the new plugin visitor API.
No concerns here.crates/biome_analyze/src/registry.rs (2)
5-5
: LGTM: switch to SignalRuleKey import.
Consistent with the new matcher keying.
441-445
: Manual verification required: automated searches didn’t locate any literalSignalEntry { rule: … }
constructions. Please manually confirm everySignalEntry
instantiation usesSignalRuleKey::Rule
(for rules) or thePlugin
variant as intended.crates/biome_rowan/src/syntax/node.rs (1)
11-11
: LGTM: added Any import.
Required for the erasure/downcast bits below.crates/biome_plugin_loader/src/analyzer_js_plugin.rs (3)
75-86
: Language + query wiring looks goodTargets JavaScript and limits evaluation to JS roots. Matches the visitor’s expectations.
174-189
: Threaded test is soundExercises thread-local loading and per-file evaluation; assertions are crisp.
87-122
: Preserve AST context or defer explicitly
- Include minimal node metadata (e.g.
kind
andrange
) in the JS entrypoint call—or document intentional deferral in the PR description and open a tracking issue.- Tag pulled diagnostics with the plugin’s name via
.map(|d| d.subcategory(plugin_name.clone()))
to avoid anonymous subcategories.Would you like a prototype passing
(path, kind, start, end)
as extra JS args?crates/biome_analyze/src/analyzer_plugin.rs (2)
19-24
: Trait surface aligns with the new visitor modelLanguage + query metadata and per-node evaluation are a solid API for syntax-time plugins.
87-92
: Range pruning: double-checkordering(range).is_ne()
does what you intendEnsure this treats “disjoint” ranges only; overlapping-but-not-containing nodes shouldn’t be skipped if that’s not desired. If the semantics are ambiguous, prefer an explicit disjoint check.
crates/biome_plugin_loader/src/analyzer_grit_plugin.rs (3)
46-63
: Language/query mapping looks correctGrit → {JS,CSS} targeting and root-kind query are consistent with the visitor.
80-119
: Diagnostic shaping is solidCarries logs, enforces spans, and annotates with plugin name; reads well.
127-179
: Helper is tidy
register_diagnostic
handles message/severity nicely; defaults are sensible.crates/biome_analyze/src/suppressions.rs (3)
225-231
: Thread plugin_name through push_suppression: OKPlumbing the optional plugin name into range suppressions is sensible and aligns with line/top-level handling. No issues spotted.
Also applies to: 239-245
342-357
: New suppress_plugin() helper: LGTMEfficient backwards scan and correct did_suppress_signal marking. No concerns.
552-560
: Range push now passes plugin_name: OKGood cohesion with the updated
RangeSuppressions::push_suppression
.crates/biome_analyze/src/lib.rs (4)
30-32
: Re-exports and SignalRuleKey import: LGTMPublic surface reflects the new plugin visitor model, and the import is scoped correctly.
Also applies to: 39-39
199-201
: Consistent, helpful “unused suppression” notesNice touch linking to the suppression that actually applied. No issues.
Also applies to: 221-223
403-430
: Top-level and range suppression handling for plugins looks correctThe new match on
SignalRuleKey
integrates plugin suppressions cleanly with existing rule paths.
455-481
: Line suppression path covers plugins; consider one edge caseLogic for instances (rules) vs plugins is sound. One behavioural question: should
// biome-ignore-start lint/plugin
without a plugin name be able to close a plugin-specific block at// biome-ignore-end lint/plugin
(no name)? At present, aRangeEnd
without a plugin name only closes an “all plugins” start. If the grammar doesn’t allow names on-end
, we might want to relax the end-side matching to close the most recent plugin-suppression regardless of name.Would you confirm the intended syntax? If you want the relaxed behaviour, I can propose a small tweak to the
PLUGIN_LINT_RULE_FILTER
end-match to fall back to the most recent non-ended plugin range whenplugin_name
isNone
.
There was a problem hiding this 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
♻️ Duplicate comments (1)
crates/biome_analyze/src/analyzer_plugin.rs (1)
110-116
: Good fix: use span() accessor instead of field accessUsing diagnostic.span() avoids visibility/compat pitfalls flagged earlier. Nice one.
🧹 Nitpick comments (4)
crates/biome_analyze/src/analyzer_plugin.rs (4)
18-24
: Prefer Arc over Arc<Box> to avoid double indirectionThe extra Box adds an unnecessary allocation and pointer chase. If ABI/public API allows, consider simplifying to Arc for AnalyzerPluginSlice/Vec and fields that store plugins.
32-36
: Struct field also inherits the double indirectionPluginVisitor.plugin mirrors the Arc<Box<...>> pattern. If you adopt Arc, update this field accordingly to keep things consistent and lean.
43-55
: Make construction safe (or guarded) by checking the plugin’s target languagenew_unchecked relies on callers to pair the correct language with the plugin. A mismatch silently no-ops (query kinds won’t match) and is painful to debug. Offer a safe constructor that validates plugin.language().
Patch sketch (adds a safe new and keeps new_unchecked for internal use):
impl<L> PluginVisitor<L> where L: Language + 'static, L::Kind: Eq + Hash, { + /// Creates a syntax visitor from the plugin, validating the target language. + pub fn new(plugin: Arc<Box<dyn AnalyzerPlugin>>, expected: PluginTargetLanguage) -> Result<Self, PluginTargetLanguage> { + let actual = plugin.language(); + if actual != expected { + return Err(actual); + } + // SAFETY: `actual == expected` guarantees the language pairing. + Ok(unsafe { Self::new_unchecked(plugin) }) + } + /// Creates a syntax visitor from the plugin. /// /// # Safety /// Do not forget to check the plugin is targeted for the language `L`. pub unsafe fn new_unchecked(plugin: Arc<Box<dyn AnalyzerPlugin>>) -> Self { let query = plugin.query().into_iter().map(L::Kind::from_raw).collect();
87-93
: No change needed:ordering(range).is_ne()
correctly skips only disjoint nodes.
- Optional: for clearer intent, you may use
node.text_range_with_trivia().intersect(range).is_none()
(be aware it treats boundary-touching as overlap).
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
crates/biome_analyze/src/analyzer_plugin.rs
(2 hunks)crates/biome_analyze/src/suppressions.rs
(6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- crates/biome_analyze/src/suppressions.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{rs,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Format Rust and TOML files before committing (use
just f
/just format
).
Files:
crates/biome_analyze/src/analyzer_plugin.rs
crates/biome_*/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place core crates under /crates/biome_*/
Files:
crates/biome_analyze/src/analyzer_plugin.rs
🧠 Learnings (4)
📚 Learning: 2025-08-17T08:56:30.831Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:56:30.831Z
Learning: Applies to crates/biome_analyze/crates/**/lib/src/**/nursery/**/*.rs : Use the local `rule_category!()` macro in diagnostics for the rule’s category, not string-parsed categories
Applied to files:
crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Specify category and severity using #[diagnostic(...)] on the type or derive them from fields
Applied to files:
crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Types implementing Diagnostic must also implement Debug (e.g., use #[derive(Debug, Diagnostic)])
Applied to files:
crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : #[derive(Diagnostic)] can be used on enums only if every variant contains a diagnostic type
Applied to files:
crates/biome_analyze/src/analyzer_plugin.rs
🧬 Code graph analysis (1)
crates/biome_analyze/src/analyzer_plugin.rs (3)
crates/biome_plugin_loader/src/analyzer_js_plugin.rs (4)
fmt
(52-56)language
(76-78)query
(80-85)evaluate
(87-122)crates/biome_rowan/src/syntax/node.rs (12)
fmt
(778-811)fmt
(815-817)fmt
(917-919)skip_subtree
(944-946)skip_subtree
(999-1001)kind
(67-69)kind
(1048-1054)kind
(1125-1125)kind
(1129-1131)kind
(1135-1137)kind
(1184-1186)new
(1152-1154)crates/biome_plugin_loader/src/analyzer_grit_plugin.rs (6)
language
(46-51)query
(53-63)evaluate
(65-120)node
(69-70)node
(72-73)None
(103-103)
⏰ 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). (23)
- GitHub Check: Bench (biome_configuration)
- GitHub Check: Bench (biome_module_graph)
- GitHub Check: Bench (biome_html_formatter)
- GitHub Check: Bench (biome_package)
- GitHub Check: Bench (biome_graphql_formatter)
- GitHub Check: Bench (biome_html_parser)
- GitHub Check: Bench (biome_graphql_parser)
- GitHub Check: Bench (biome_json_formatter)
- GitHub Check: Bench (biome_css_analyze)
- GitHub Check: Bench (biome_json_analyze)
- GitHub Check: Bench (biome_js_analyze)
- GitHub Check: Bench (biome_json_parser)
- GitHub Check: Bench (biome_css_formatter)
- GitHub Check: Bench (biome_js_formatter)
- GitHub Check: Bench (biome_js_parser)
- GitHub Check: Bench (biome_css_parser)
- GitHub Check: Test (depot-windows-2022-16)
- GitHub Check: Test (depot-ubuntu-24.04-arm-16)
- GitHub Check: Documentation
- GitHub Check: Check Dependencies
- GitHub Check: Parser conformance
- GitHub Check: Test Node.js API
- GitHub Check: autofix
6b66586
to
9f09a10
Compare
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/biome_analyze/src/suppressions.rs (1)
107-109
: Fix: cover() return value is ignored in TopLevelSuppression.expand_rangeYou’re dropping the result of TextRange::cover; the top-level range never grows.
- pub(crate) fn expand_range(&mut self, range: TextRange) { - self.range.cover(range); - } + pub(crate) fn expand_range(&mut self, range: TextRange) { + self.range = self.range.cover(range); + }
🧹 Nitpick comments (4)
crates/biome_analyze/src/suppressions.rs (4)
191-197
: Docs/style nit: wording consistency
- “Set to true if this comment suppress all plugins” → “suppresses”.
- Consider aligning field naming with TopLevelSuppression (“plugins” vs “suppressed_plugins”) for symmetry.
208-211
: Minor: prefer explicit false over Default::default() for boolClearer at a glance and avoids type inference surprises.
- suppress_all_plugins: Default::default(), + suppress_all_plugins: false,
229-233
: Avoid plugin name allocations: pass &str through the pipelineNo need to allocate a String here; accept Option<&str> and only allocate when inserting into the set.
- pub(crate) fn push_suppression( + pub(crate) fn push_suppression( &mut self, suppression: &AnalyzerSuppression, filter: Option<RuleFilter<'static>>, - plugin_name: Option<String>, + plugin_name: Option<&str>, text_range: TextRange, already_suppressed: Option<TextRange>, ) -> Result<(), AnalyzerSuppressionDiagnostic> { @@ - Some(PLUGIN_LINT_RULE_FILTER) => { - if let Some(plugin_name) = plugin_name { - range_suppression.suppressed_plugins.insert(plugin_name); - } else { + Some(PLUGIN_LINT_RULE_FILTER) => { + if let Some(plugin_name) = plugin_name { + range_suppression + .suppressed_plugins + .insert(plugin_name.to_string()); + } else { range_suppression.suppress_all_plugins = true; - } + } }Also applies to: 239-245
551-559
: Plumb plugin name by reference to avoid copiesFollow-up to the earlier suggestion: pass &str into RangeSuppressions::push_suppression.
- self.range_suppressions.push_suppression( + self.range_suppressions.push_suppression( suppression, filter, - plugin_name, + plugin_name.as_deref(), comment_range, already_suppressed, )Optionally, consider marking plugin-level “already suppressed” to match rule-level behaviour:
- Add a helper (outside the changed hunk):
impl RangeSuppressions { pub(crate) fn matches_plugin_in_range( &self, plugin_name: &str, position: &TextRange, ) -> Option<TextRange> { for s in self.suppressions.iter().rev() { if s.suppression_range.contains_range(*position) && (s.suppress_all_plugins || s.suppressed_plugins.contains(plugin_name)) { return Some(s.suppression_range); } } None } }
- Then, in push_suppression (before matching on suppression.variant), enrich already_suppressed for plugin suppressions:
let mut already_suppressed = self.already_suppressed(filter.as_ref(), &comment_range); if matches!(filter, Some(PLUGIN_LINT_RULE_FILTER)) { if self.top_level_suppression.suppress_all_plugins || plugin_name .as_ref() .is_some_and(|n| self.top_level_suppression.suppressed_plugin(n)) { already_suppressed = Some(self.top_level_suppression.comment_range); } else if let Some(name) = plugin_name.as_deref() { if let Some(r) = self .range_suppressions .matches_plugin_in_range(name, &comment_range) { already_suppressed = Some(r); } } }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
crates/biome_analyze/src/analyzer_plugin.rs
(2 hunks)crates/biome_analyze/src/suppressions.rs
(6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- crates/biome_analyze/src/analyzer_plugin.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{rs,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Format Rust and TOML files before committing (use
just f
/just format
).
Files:
crates/biome_analyze/src/suppressions.rs
crates/biome_*/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place core crates under /crates/biome_*/
Files:
crates/biome_analyze/src/suppressions.rs
⏰ 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). (25)
- GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
- GitHub Check: Documentation
- GitHub Check: Lint project (depot-windows-2022)
- GitHub Check: Test (depot-windows-2022-16)
- GitHub Check: Test (depot-ubuntu-24.04-arm-16)
- GitHub Check: Check Dependencies
- GitHub Check: Bench (biome_module_graph)
- GitHub Check: Bench (biome_css_analyze)
- GitHub Check: Bench (biome_configuration)
- GitHub Check: Bench (biome_package)
- GitHub Check: Bench (biome_json_analyze)
- GitHub Check: Bench (biome_html_formatter)
- GitHub Check: Bench (biome_json_formatter)
- GitHub Check: Bench (biome_graphql_parser)
- GitHub Check: Bench (biome_html_parser)
- GitHub Check: Bench (biome_graphql_formatter)
- GitHub Check: Bench (biome_css_parser)
- GitHub Check: Bench (biome_js_analyze)
- GitHub Check: Bench (biome_js_parser)
- GitHub Check: Bench (biome_css_formatter)
- GitHub Check: Bench (biome_json_parser)
- GitHub Check: Bench (biome_js_formatter)
- GitHub Check: Test Node.js API
- GitHub Check: autofix
- GitHub Check: Parser conformance
🔇 Additional comments (1)
crates/biome_analyze/src/suppressions.rs (1)
341-355
: LGTM: clean, mirrors suppress_rule and marks did_suppress_signalNo concerns here.
cf945b4
to
19d8cc4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
crates/biome_analyze/src/suppressions.rs (2)
259-267
: Unify diagnostic wording: use “biome-ignore-*” consistentlyElsewhere you use “biome-ignore-*”. Let’s align this message too.
- markup!{"Found a "<Emphasis>"biome-range-end"</Emphasis>" suppression without a "<Emphasis>"biome-range-start"</Emphasis>" suppression. This is invalid"} + markup!{"Found a "<Emphasis>"biome-ignore-end"</Emphasis>" suppression without a "<Emphasis>"biome-ignore-start"</Emphasis>" suppression. This is invalid"}
270-295
: Bug: generic biome-ignore-end drops state instead of closing the last open suppressionPopping and returning early skips marking
is_ended
and doesn’t extend the range to include the end comment. Close the most recent open suppression instead, mirroring the other branches.- let range_suppression = match filter { - None => { - self.suppressions.pop(); - return Ok(()); - } + let range_suppression = match filter { + None => self + .suppressions + .iter_mut() + .rev() + .find(|s| !s.is_ended), Some(PLUGIN_LINT_RULE_FILTER) => self .suppressions .iter_mut() .rev() .filter(|s| !s.is_ended) .find(|s| match &plugin_name { Some(plugin_name) => s.suppressed_plugins.contains(plugin_name), None => s.suppress_all_plugins, }), Some(filter) => self .suppressions .iter_mut() .rev() .filter(|s| !s.is_ended) .find(|s| { s.filters_by_category .get(&suppression.category) .is_some_and(|filters| filters.contains(&filter)) }), };
🧹 Nitpick comments (3)
crates/biome_analyze/src/suppressions.rs (3)
191-197
: Naming consistency + doc nitRange uses
suppressed_plugins
while top-level usesplugins
. Consider aligning names for symmetry. Also fix the grammar in the doc string.- /// Set to true if this comment suppress all plugins + /// Set to true if this comment suppresses all plugins
208-211
: Prefer explicitfalse
overDefault::default()
for boolsTiny readability win; keeps intent obvious.
- suppressed_plugins: Default::default(), - suppress_all_plugins: Default::default(), + suppressed_plugins: Default::default(), + suppress_all_plugins: false,
107-109
: Bug:cover()
result is ignored for top-level expandThis never updates
range
. Assign the result.- self.range.cover(range); + self.range = self.range.cover(range);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
crates/biome_analyze/src/suppressions.rs
(6 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{rs,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Format Rust and TOML files before committing (use
just f
/just format
).
Files:
crates/biome_analyze/src/suppressions.rs
crates/biome_*/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place core crates under /crates/biome_*/
Files:
crates/biome_analyze/src/suppressions.rs
⏰ 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). (23)
- GitHub Check: Test Node.js API
- GitHub Check: Documentation
- GitHub Check: Check Dependencies
- GitHub Check: Test (depot-ubuntu-24.04-arm-16)
- GitHub Check: Test (depot-windows-2022-16)
- GitHub Check: Lint project (depot-windows-2022)
- GitHub Check: Bench (biome_html_formatter)
- GitHub Check: Bench (biome_module_graph)
- GitHub Check: Bench (biome_configuration)
- GitHub Check: Bench (biome_html_parser)
- GitHub Check: Bench (biome_graphql_formatter)
- GitHub Check: Bench (biome_graphql_parser)
- GitHub Check: Parser conformance
- GitHub Check: Bench (biome_json_formatter)
- GitHub Check: Bench (biome_json_parser)
- GitHub Check: Bench (biome_js_formatter)
- GitHub Check: Bench (biome_json_analyze)
- GitHub Check: Bench (biome_js_analyze)
- GitHub Check: Bench (biome_css_analyze)
- GitHub Check: Bench (biome_js_parser)
- GitHub Check: Bench (biome_css_formatter)
- GitHub Check: Bench (biome_css_parser)
- GitHub Check: autofix
🔇 Additional comments (5)
crates/biome_analyze/src/suppressions.rs (5)
239-245
: LGTM: plugin range-start handlingCorrectly records specific plugin vs “all plugins”. Nicely done.
296-301
: LGTM: end-range now expandssuppression_range
Correctly marks ended and covers the end-comment span.
341-355
: LGTM: plugin suppression matchingLinear scan from the back with
did_suppress_signal
toggle is appropriate for typical counts.
551-559
: LGTM: plumbsplugin_name
into range suppressionsSignature alignment looks correct with the updated push.
229-231
: Verify allpush_suppression
call sites
Ripgrep returned no matches; please manually ensure every invocation properly passes the newplugin_name
parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing work, thank you!
You might want to add a changeset still for the improved suppressions with plugins? |
if let Some(range) = ctx.range | ||
&& node.text_range_with_trivia().ordering(range).is_ne() | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do we do here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I just copied it from SyntaxVisitor
, and honestly I am not sure what do we do here :(
biome/crates/biome_analyze/src/syntax.rs
Lines 65 to 87 in 7638e84
let node = match event { | |
WalkEvent::Enter(node) => node, | |
WalkEvent::Leave(node) => { | |
if let Some(skip_subtree) = &self.skip_subtree | |
&& skip_subtree == node | |
{ | |
self.skip_subtree = None; | |
} | |
return; | |
} | |
}; | |
if self.skip_subtree.is_some() { | |
return; | |
} | |
if let Some(range) = ctx.range | |
&& node.text_range_with_trivia().ordering(range).is_ne() | |
{ | |
self.skip_subtree = Some(node.clone()); | |
return; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that ctx
can provide a range within which diagnostics should be pulled, instead of running analysis on the entire tree. So this check is just to make sure that the node being checked is within that range.
crates/biome_js_analyze/tests/plugin/preferObjectSpreadSuppression.grit.snap
Show resolved
Hide resolved
crates/biome_js_analyze/tests/plugin/preferObjectSpreadSuppression.grit.snap
Show resolved
Hide resolved
|
||
/// Opaque struct for [`SyntaxNode`] without the `L: Language` constraint. | ||
#[derive(Debug)] | ||
pub struct AnySyntaxNode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the advantage of using AnySyntaxNode
over the SendNode
type we already have? In the Grit plugin we can see that the nodes are directly converted to a SendNode
anyway, so why don't we just use SendNode
everywhere instead of introducing a new type here?
Nevermind, figured out the answer: Because SendNode
can only be reliably used for root nodes :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I introduced AnySyntaxNode
because it's safe to use with any descendants but !Send
. I am not sure whether the limitation of SendNode
can be lifted and merged into AnySyntaxNode
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
crates/biome_plugin_loader/src/analyzer_js_plugin.rs (1)
88-123
: Propagate plugin name into diagnostics for suppression matchingTo enable biome-ignore lint/plugin/ suppressions for JS plugins, tag emitted diagnostics with the plugin name as subcategory (e.g. file-stem), similar to the Grit path.
- fn evaluate(&self, _node: AnySyntaxNode, path: Arc<Utf8PathBuf>) -> Vec<RuleDiagnostic> { + fn evaluate(&self, _node: AnySyntaxNode, path: Arc<Utf8PathBuf>) -> Vec<RuleDiagnostic> { + let plugin_name = self + .path + .file_stem() + .map(|s| s.to_string()) + .unwrap_or_else(|| "anonymous".to_string()); let mut plugin = match self .loaded .get_mut_or_try_init(|| load_plugin(self.fs.clone(), &self.path)) { Ok(plugin) => plugin, Err(err) => { return vec![RuleDiagnostic::new( category!("plugin"), None::<TextRange>, markup!("Could not load the plugin: "<Error>{err.to_string()}</Error>), )]; } }; let plugin = plugin.deref_mut(); // TODO: pass the AST to the plugin plugin .ctx .call_function( &plugin.entrypoint, &JsValue::undefined(), &[JsValue::String(JsString::from(path.as_str()))], ) .map_or_else( |err| { vec![RuleDiagnostic::new( category!("plugin"), None::<TextRange>, markup!("Plugin errored: "<Error>{err.to_string()}</Error>), )] }, - |_| plugin.ctx.pull_diagnostics(), + |_| { + plugin + .ctx + .pull_diagnostics() + .into_iter() + .map(|d| d.subcategory(plugin_name.clone())) + .collect() + }, ) }If the runtime already tags diagnostics with a subcategory, feel free to ignore; otherwise this aligns JS plugins with the new suppression model. I can follow up with a small PR if you prefer.
crates/biome_analyze/src/suppressions.rs (1)
107-109
: Bug: top-level suppression range never expands (cover() result is ignored)
TextRange::cover
returns a new range; you’re dropping it, sorange
stays default. This breaks accurate highlighting/accounting of top-level suppression span.pub(crate) fn expand_range(&mut self, range: TextRange) { - self.range.cover(range); + self.range = self.range.cover(range); }
♻️ Duplicate comments (3)
crates/biome_analyze/src/matcher.rs (1)
147-151
: Nice DX win implementing FromThis matches previous feedback and smooths call-sites converting to SignalRuleKey.
crates/biome_analyze/src/analyzer_plugin.rs (1)
107-116
: Avoid “anonymous” plugin keys; ensure stable identity for per-plugin suppressionsFalling back to "anonymous" breaks per-plugin suppression for JS plugins (subcategory isn’t set there). Either make plugin identity explicit on the trait, or ensure JS plugins set a stable subcategory. This was raised before; still unresolved here.
Option A (preferred, explicit key on the trait):
@@ pub trait AnalyzerPlugin: Debug + Send + Sync { fn language(&self) -> PluginTargetLanguage; fn query(&self) -> Vec<RawSyntaxKind>; fn evaluate(&self, node: AnySyntaxNode, path: Arc<Utf8PathBuf>) -> Vec<RuleDiagnostic>; + + /// Stable identity used for suppressions and reporting. + fn key(&self) -> std::borrow::Cow<'static, str>; } @@ - let name = diagnostic - .subcategory - .clone() - .unwrap_or_else(|| "anonymous".into()); + let name = diagnostic + .subcategory + .clone() + .unwrap_or_else(|| (&*self.plugin).key().into_owned());Option B (minimal churn): in crates/biome_plugin_loader/src/analyzer_js_plugin.rs, map pulled diagnostics to set a stable subcategory (e.g. plugin file stem) before returning:
let name = self .path .file_stem() .map(|s| s.to_string()) .unwrap_or_else(|| "anonymous".to_string()); plugin .ctx .pull_diagnostics() .into_iter() .map(|d| d.subcategory(name.clone())) .collect()Run to confirm no “anonymous” subcategories remain for JS plugins:
#!/bin/bash rg -n --type=rust -C2 'pull_diagnostics\(\).*collect' crates/biome_plugin_loader | sed -n '1,200p' rg -n --type=rust -C2 'subcategory\(' crates/biome_plugin_loader/src/analyzer_js_plugin.rs || echo "No subcategory set in JS plugin loader"crates/biome_analyze/src/suppressions.rs (1)
278-283
: Generic biome-ignore-end shouldn’t pop and drop statePopping removes the suppression entirely, which prevents “unused range suppression” diagnostics and loses context. Instead, close the latest open suppression (any kind), mark it ended, and extend the range to include the end comment.
- None => { - self.suppressions.pop(); - return Ok(()); - } + None => self + .suppressions + .iter_mut() + .rev() + .find(|s| !s.is_ended), @@ - if let Some(existing_suppression) = range_suppression { + if let Some(existing_suppression) = range_suppression { // Mark this as ended and expand it by the text range of this comment existing_suppression.is_ended = true; existing_suppression.suppression_range = existing_suppression.suppression_range.cover(text_range); } else {
🧹 Nitpick comments (10)
crates/biome_analyze/src/matcher.rs (2)
141-151
: Good abstraction; consider deriving Eq/Hash and a Display implSignalRuleKey cleanly captures both core rules and plugins. To ease use in maps/sets and logging, derive Eq/Hash and add Display.
-#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum SignalRuleKey { Rule(RuleKey), Plugin(Box<str>), } + +impl std::fmt::Display for SignalRuleKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SignalRuleKey::Rule(k) => k.fmt(f), + SignalRuleKey::Plugin(name) => write!(f, "plugin/{name}"), + } + } +}
153-165
: Documentation nit: include plugins in the field docThe field comment still says “rule”; it now also represents plugin diagnostics.
- /// Unique identifier for the rule that emitted this signal + /// Unique identifier for the rule or plugin that emitted this signal pub rule: SignalRuleKey,crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.grit (1)
1-9
: Confirm plugin name used for suppressionsSuppressions in the CSS fixture target lint/plugin/useLowercaseColorsSuppression. Ensure this rule’s emitted diagnostics use that exact plugin name (e.g. file-stem) as the subcategory; otherwise the suppressions won’t match. If the Grit DSL supports an explicit name, consider declaring it to make this deterministic.
crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.css (1)
13-16
: Minor consistency: drop trailing semicolon in directiveOne directive has a trailing semicolon inside the comment; others don’t. For consistency:
- /* biome-ignore lint/plugin/anotherPlugin: reason; */ + /* biome-ignore lint/plugin/anotherPlugin: reason */crates/biome_plugin_loader/src/analyzer_js_plugin.rs (2)
76-86
: Scoped query to JS roots is fine; keep an eye on granularityLimiting to AnyJsRoot ensures evaluate runs once per file. The TODO about granular queries from JS plugins is spot on; wiring that later will avoid running whole-file plugins unnecessarily.
105-112
: Follow-up: plumb AST to JS pluginsLeaving a TODO is fine for this PR. Next step: serialise a minimal AST facade (or pass a node handle) so plugins can truly act as syntax visitors and avoid re-parsing or relying on global state.
crates/biome_analyze/src/analyzer_plugin.rs (3)
89-95
: Range pruning: use intersection for clarityThe ordering check is harder to parse. Using an explicit intersection reads clearer and avoids subtle ordering semantics.
- if let Some(range) = ctx.range - && node.text_range_with_trivia().ordering(range).is_ne() - { + if let Some(range) = ctx.range + && node.text_range_with_trivia().intersect(range).is_none() + { self.skip_subtree = Some(node.clone()); return; }
49-57
: Make the unsafe constructor safer in debug buildsAdd a debug assertion that the plugin language matches
L
to catch misuse early. If you can’t derivePluginTargetLanguage
fromL
here, place this assert at the call sites that know the language.
32-38
: Avoid double indirection for pluginsUsing
Arc<Box<dyn AnalyzerPlugin>>
is an unnecessary extra hop. PreferArc<dyn AnalyzerPlugin>
across the API when feasible.crates/biome_analyze/src/lib.rs (1)
73-76
: Docstring is outdated; plugins now run as visitorsThis still claims plugins “do not support the same visitor pattern” which is no longer true after this PR. Please update to avoid confusing readers.
Suggested rewording:
- “The analyzer also supports plugins as syntax visitors. They respect the same suppression comments and report signals in the same format.”
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.grit.snap
is excluded by!**/*.snap
and included by**
📒 Files selected for processing (9)
.changeset/fresh-terms-carry.md
(1 hunks)crates/biome_analyze/src/analyzer_plugin.rs
(2 hunks)crates/biome_analyze/src/lib.rs
(5 hunks)crates/biome_analyze/src/matcher.rs
(3 hunks)crates/biome_analyze/src/registry.rs
(2 hunks)crates/biome_analyze/src/suppressions.rs
(6 hunks)crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.css
(1 hunks)crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.grit
(1 hunks)crates/biome_plugin_loader/src/analyzer_js_plugin.rs
(4 hunks)
✅ Files skipped from review due to trivial changes (1)
- .changeset/fresh-terms-carry.md
🚧 Files skipped from review as they are similar to previous changes (1)
- crates/biome_analyze/src/registry.rs
🧰 Additional context used
📓 Path-based instructions (4)
crates/biome_*_{syntax,parser,formatter,analyze,factory,semantic}/**
📄 CodeRabbit inference engine (CLAUDE.md)
Maintain the per-language crate structure: biome_{lang}_{syntax,parser,formatter,analyze,factory,semantic}
Files:
crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.css
crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.grit
crates/biome_*/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place core crates under /crates/biome_*/
Files:
crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.css
crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.grit
crates/biome_analyze/src/matcher.rs
crates/biome_analyze/src/analyzer_plugin.rs
crates/biome_analyze/src/lib.rs
crates/biome_plugin_loader/src/analyzer_js_plugin.rs
crates/biome_analyze/src/suppressions.rs
**/tests/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place test files under a tests/ directory in each crate
Files:
crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.css
crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.grit
**/*.{rs,toml}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Format Rust and TOML files before committing (use
just f
/just format
).
Files:
crates/biome_analyze/src/matcher.rs
crates/biome_analyze/src/analyzer_plugin.rs
crates/biome_analyze/src/lib.rs
crates/biome_plugin_loader/src/analyzer_js_plugin.rs
crates/biome_analyze/src/suppressions.rs
🧠 Learnings (8)
📚 Learning: 2025-08-17T08:56:30.831Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:56:30.831Z
Learning: Applies to crates/biome_analyze/crates/biome_js_analyze/tests/quick_test.rs : Use `biome_js_analyze/tests/quick_test.rs` for quick, ad-hoc testing; un-ignore the test and adjust the rule filter as needed
Applied to files:
crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.grit
📚 Learning: 2025-08-17T08:56:30.831Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:56:30.831Z
Learning: Applies to crates/biome_analyze/crates/biome_js_analyze/lib/src/lint/nursery/*.rs : For new JavaScript lint rules generated by `just new-js-lintrule`, implement the rule in the generated file under `biome_js_analyze/lib/src/lint/nursery/`
Applied to files:
crates/biome_css_analyze/tests/plugin/useLowercaseColorsSuppression.grit
crates/biome_plugin_loader/src/analyzer_js_plugin.rs
📚 Learning: 2025-08-17T08:56:30.831Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:56:30.831Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Define per-rule options in the `biome_rule_options` crate under `lib/`, with serde- and schemars-compatible derives and `#[serde(rename_all = "camelCase", deny_unknown_fields, default)]`
Applied to files:
crates/biome_analyze/src/matcher.rs
📚 Learning: 2025-08-17T08:56:30.831Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:56:30.831Z
Learning: Applies to crates/biome_analyze/crates/**/lib/src/**/nursery/**/*.rs : Use the local `rule_category!()` macro in diagnostics for the rule’s category, not string-parsed categories
Applied to files:
crates/biome_analyze/src/analyzer_plugin.rs
crates/biome_analyze/src/lib.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Specify category and severity using #[diagnostic(...)] on the type or derive them from fields
Applied to files:
crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Types implementing Diagnostic must also implement Debug (e.g., use #[derive(Debug, Diagnostic)])
Applied to files:
crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : #[derive(Diagnostic)] can be used on enums only if every variant contains a diagnostic type
Applied to files:
crates/biome_analyze/src/analyzer_plugin.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/crates/biome_diagnostics_categories/src/categories.rs : When declaring a new diagnostic category, register it in crates/biome_diagnostics_categories/src/categories.rs
Applied to files:
crates/biome_analyze/src/lib.rs
🧬 Code graph analysis (4)
crates/biome_analyze/src/matcher.rs (2)
crates/biome_analyze/src/registry.rs (3)
RuleKey
(441-441)new
(298-300)new
(382-455)crates/biome_analyze/src/context.rs (1)
RuleKey
(42-42)
crates/biome_analyze/src/analyzer_plugin.rs (5)
crates/biome_plugin_loader/src/analyzer_js_plugin.rs (4)
fmt
(52-56)language
(76-78)query
(80-86)evaluate
(88-123)crates/biome_rowan/src/syntax/node.rs (11)
fmt
(778-811)fmt
(815-817)fmt
(917-919)kind
(67-69)kind
(1048-1054)kind
(1125-1125)kind
(1129-1131)kind
(1135-1137)kind
(1184-1186)new
(1152-1154)default
(923-928)crates/biome_plugin_loader/src/analyzer_grit_plugin.rs (6)
language
(46-51)query
(53-63)evaluate
(65-120)node
(69-70)node
(72-73)None
(103-103)crates/biome_rowan/src/syntax.rs (3)
node
(100-102)from_raw
(40-40)new
(74-76)crates/biome_analyze/src/registry.rs (2)
new
(298-300)new
(382-455)
crates/biome_analyze/src/lib.rs (1)
crates/biome_analyze/src/matcher.rs (1)
rule
(113-115)
crates/biome_plugin_loader/src/analyzer_js_plugin.rs (3)
crates/biome_analyze/src/analyzer_plugin.rs (3)
language
(19-19)query
(21-21)evaluate
(23-23)crates/biome_plugin_loader/src/analyzer_grit_plugin.rs (3)
language
(46-51)query
(53-63)evaluate
(65-120)crates/biome_rowan/src/syntax/node.rs (7)
kind
(67-69)kind
(1048-1054)kind
(1125-1125)kind
(1129-1131)kind
(1135-1137)kind
(1184-1186)new
(1152-1154)
⏰ 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). (23)
- GitHub Check: Bench (biome_json_parser)
- GitHub Check: Bench (biome_package)
- GitHub Check: Bench (biome_json_analyze)
- GitHub Check: Bench (biome_configuration)
- GitHub Check: Bench (biome_css_analyze)
- GitHub Check: Bench (biome_graphql_formatter)
- GitHub Check: Bench (biome_module_graph)
- GitHub Check: Bench (biome_graphql_parser)
- GitHub Check: Bench (biome_html_parser)
- GitHub Check: Bench (biome_js_parser)
- GitHub Check: Bench (biome_html_formatter)
- GitHub Check: Bench (biome_js_formatter)
- GitHub Check: Bench (biome_js_analyze)
- GitHub Check: Bench (biome_css_formatter)
- GitHub Check: Bench (biome_css_parser)
- GitHub Check: Bench (biome_json_formatter)
- GitHub Check: Documentation
- GitHub Check: Test (depot-ubuntu-24.04-arm-16)
- GitHub Check: Check Dependencies
- GitHub Check: Test (depot-windows-2022-16)
- GitHub Check: Test Node.js API
- GitHub Check: Parser conformance
- GitHub Check: autofix
🔇 Additional comments (6)
crates/biome_analyze/src/matcher.rs (2)
258-258
: Tests updated correctly to use into()This keeps the test faithful to the new API while remaining readable.
153-165
: AllSignalEntry
call-sites now useSignalRuleKey
; no bareRuleKey
initialisers remain.crates/biome_plugin_loader/src/analyzer_js_plugin.rs (1)
175-176
: Test updates look goodPassing parse.syntax().into() matches the new evaluate signature and keeps the concurrency test meaningful.
Also applies to: 189-190
crates/biome_analyze/src/lib.rs (1)
410-431
: Suppression matching for plugins looks goodThe split between Rule vs Plugin with top-level and range suppressions is clear and consistent with the new model.
crates/biome_analyze/src/suppressions.rs (2)
349-366
: Range plugin suppression helper: nice and tidyGood encapsulation; the semantics align with line/top-level plugin suppression.
97-101
: Cross-type equality confirmed
impl PartialEq<RuleKey> for RuleFilter<'static>
at crates/biome_analyze/src/matcher.rs:132 ensuresf == filter
compiles.
Summary
This pull request integrates Grit/JS plugins as syntax visitors that runs on the analyser. Previously, plugins are used to run separately, after all phases are run. To support querying AST nodes in JS plugins, we need to convert a plugin into an AST visitor and run it together with any other rules.
As a plus, I also integrated suppressions for plugins to other analyser suppressions, and range suppression are now supported for plugin diagnostics.
Test Plan
Existing tests should pass.
Docs
N/A