From a9e285a85df3a5f2111025b767d736acded111cb Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Tue, 1 Jul 2025 08:45:12 +0100 Subject: [PATCH 1/2] docs: update analyzer contribution guide --- crates/biome_analyze/CONTRIBUTING.md | 35 ++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/crates/biome_analyze/CONTRIBUTING.md b/crates/biome_analyze/CONTRIBUTING.md index bb375c364aa2..69f3c071ba06 100644 --- a/crates/biome_analyze/CONTRIBUTING.md +++ b/crates/biome_analyze/CONTRIBUTING.md @@ -14,6 +14,7 @@ The analyzer allows implementors to create **three different** types of rules: - [Analyzer](#analyzer) * [Table of Contents](#table-of-contents) + * [Understanding Biome Linter](#understanding-biome-linter) * [Creating a Rule](#creating-a-rule) + [Guidelines](#guidelines) - [Naming Conventions for Rules](#naming-conventions-for-rules) @@ -56,6 +57,15 @@ The analyzer allows implementors to create **three different** types of rules: + [Committing your work](#committing-your-work) + [Sidenote: Deprecating a rule](#sidenote-deprecating-a-rule) +## Understanding Biome Linter + +Biome linter is meant to work *across languages*, which means that a rule can work within multiple languages. +That's why **it's important to choose a good name for your rule**. If the name of the rule is very generic, it means that +it could potentially be implemented for multiple languages. However, if a rule is meant for a specific language, you should +choose a name that is more specific. + +Understanding this is important because it might have repercussions on how rule options will be applied to different languages. + ## Creating a Rule When creating or updating a rule, you need to be aware that there's a lot of generated code inside our toolchain. @@ -539,6 +549,12 @@ Some rules may allow customization [using per-rule options in `biome.json`](http > > If provided, options should follow our [technical philosophy](https://biomejs.dev/internals/philosophy/#technical). +Rule options must be placed inside the crate `biome_rule_options`. If you run the command `just gen-analyzer`, the codegen +should have created a new file inside the crate that has the name of your rule. For example, if the rule name is `useThisConvention` +you should see a file `use_this_convention.rs` inside `biome_rule_options/lib`. Inside this file you'll see a struct called `UseThisConventionOptions`. + +Use this struct to add the options. + ##### Options for our example rule Let's assume that the rule we want to implement supports the following options: @@ -603,11 +619,13 @@ for you. With these types in place, you can set the associated type `Options` of the rule: ```rust -impl Rule for MyRule { +use biome_rule_options::use_my_rule::UseMyRuleOptions; + +impl Rule for UseMyRule { type Query = Semantic; type State = Fix; type Signals = Vec; - type Options = MyRuleOptions; + type Options = UseMyRuleOptions; } ``` @@ -639,18 +657,19 @@ Also, we use other `serde` macros to adjust the JSON configuration: - `deny_unknown_fields`: it raises an error if the configuration contains extraneous fields. - `default`: it uses the `Default` value when the field is missing from `biome.json`. This macro makes the field optional. -Because we use `schemars`to generate a JSON schema for `biome.json`, our options type must support the `schemars::JsonSchema` trait as well. +Because we use `schema`to generate a JSON schema for `biome.json`, our options type must support the `schemars::JsonSchema` trait as well. -You can simply use the derive macros provided by `serde`, `biome_deserialize` and `schemars` to generate the necessary implementations automatically: +You can simply use the derive macros provided by `serde`, `biome_deserialize` and `schema` to generate the necessary implementations automatically: ```rust +// crates/biome_rule_options/lib/use_my_rule.rs use biome_deserialize_macros::Deserializable; use serde::{Deserialize, Serialize}; #[derive(Debug, Default, Clone, Serialize, Deserialize, Deserializable)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[serde(rename_all = "camelCase", deny_unknown_fields, default)] -pub struct MyRuleOptions { +pub struct UseMyRuleOptions { #[serde(default, skip_serializing_if = "is_default")] main_behavior: Behavior, @@ -659,13 +678,15 @@ pub struct MyRuleOptions { } #[derive(Debug, Default, Clone)] -#[cfg_attr(feature = "schemars", derive(JsonSchema))] +#[cfg_attr(feature = "schema", derive(JsonSchema))] pub enum Behavior { #[default] A, B, C, } + +const fn is_default() -> bool { true } ``` ##### Testing & Documenting Rule Options From e674fe3ad2d19c135b09b035f8e8935130817c58 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Tue, 1 Jul 2025 09:57:47 +0100 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Marat Dulin --- crates/biome_analyze/CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/biome_analyze/CONTRIBUTING.md b/crates/biome_analyze/CONTRIBUTING.md index 69f3c071ba06..8575de819ea5 100644 --- a/crates/biome_analyze/CONTRIBUTING.md +++ b/crates/biome_analyze/CONTRIBUTING.md @@ -657,9 +657,9 @@ Also, we use other `serde` macros to adjust the JSON configuration: - `deny_unknown_fields`: it raises an error if the configuration contains extraneous fields. - `default`: it uses the `Default` value when the field is missing from `biome.json`. This macro makes the field optional. -Because we use `schema`to generate a JSON schema for `biome.json`, our options type must support the `schemars::JsonSchema` trait as well. +Because we use `schemars` to generate a JSON schema for `biome.json`, our options type must support the `schemars::JsonSchema` trait as well. -You can simply use the derive macros provided by `serde`, `biome_deserialize` and `schema` to generate the necessary implementations automatically: +You can simply use the derive macros provided by `serde`, `biome_deserialize` and `schemars` to generate the necessary implementations automatically: ```rust // crates/biome_rule_options/lib/use_my_rule.rs