Replies: 12 comments 31 replies
-
I really like the idea. I have been advocating a flatter configuration and a tag system (here ruleSets) for some time :) Here some comments and suggestions: Rule setsI wonder if {
"linter": {
"ignore": ["./dist"],
"recommended": true,
"pedantic": false,
"style": true,
"noBlankTarget": "off",
}
} Just to be sure, a rule is enabled if at least one rule set to which it belongs is enabled (or if it is individually enabled), right? I wonder if we should not switch to levels instead of Boolean for the rule sets. This could allow setting a diagnostic level for an entire rule set: {
"linter": {
"ignore": ["./dist"],
"recommended": "error",
"pedantic": "warn",
"style": "off",
"noBlankTarget": "off",
}
} By the way, I think we should keep a base subset of disjoint rule sets (i.e. the actual categories), and add rule sets when it is useful (react, jest, ...). Note that we should not introduce a
|
Beta Was this translation helpful? Give feedback.
-
I think having both rule sets and project kinds is confusing. Why not combine the two concepts? |
Beta Was this translation helpful? Give feedback.
-
I have done some research in order to make a proposal for revamping linter configuration. State of the artClippyA Clippy lint rule emits diagnostics with a given severity level among
A user can set the severity level of a rule, a group, or the meta group
For example, let's assume we have the following configuration: [lints.clippy]
all = "warn"
pedantic = "warn"
empty_enum = "allow" And we use the following command ( cargo clippy -- -A clippy::all -D clippy::empty_enum Taking the CLI options into account, we obtain the following in-memory config: [lints.clippy]
all = "allow"
pedantic = "warn"
empty_enum = "deny" This disables all rules, then set all rules of Clippy provides also a dynamic group named Some observations and remarks:
Rustc linterRustc organizes rule into groups.
A user can set a severity level on an entire group. RuffRuff implements more than 700 rules from 50 distinct sources (plugins in Ruff terminology). Ruff allows selecting or ignoring a given code or any prefix of codes. Ruff also provides the code Similarly to Clippy, Ruff uses precedence rules to determine whether a rule is selected or ignored.
To select unstable rules, a user must turn on the Some observations and remarks:
TypeScript ESLintESLint rules have an associated severity level among ESLint provides plugins to add more linter rules. ESLint plugins provide presets of rules by relying on ESLint's configuration extension.
And 3 derived presets that include rules that require type checking:
It also provides the Some observations and remarks:
Biome (current state)Biome organizes its rules into exclusive groups.
Biome provides two presets: A rule is associated to a severity level among A CLI flag Some observations and remarks:
Proposal V1The Biome linter is more complex than any other reviewed linter, This proposal takes inspiration of both Clippy and Ruff. A rule is either stable or unstable (experimental / in a nursery state) and is either enabled or disabled. Every stable rule belongs to a unique group ( A rule is associated to a severity level among A rule belongs to one or several (most likely one) domains. A rule is enabled if and only if it is individually enabled or if its group and at least one of its domain are enabled. By default, a set of groups and domains are enabled. I think we should separate rules' options in a dedicated field. Let's take an example: {
"experimental": true, // make possible to individually enable an unstable rule
"linter": {
"enabled": true,
"groups": { // enable/disable groups
"correctness": true,
"idiomatic": true,
"style": false
},
"domains": { // enable/disable domains
"default": true,
"jest": true,
"react": false
},
"rules": { // Individually enables/disables rules
"useConsistentArraySyntax": true,
"useReactHooks": true,
"noSuperWithoutExtends": false,
"useAnUnstableRule": true // Setting this unstable rule causes an error if `experimental` isn't `true`
},
"options": { // rules' options
"useConsistentArraySyntax": {
"syntax": "shorthand"
},
"useNamingConvention": {
"enumMemberCase": "Pascal"
}
}
}
} In the preceding configuration, the user explicitly:
Some remarks and questions:
To bring some compatibility with the current configuration:
EDIT: taking feedbacks into account, I wrote a second version. |
Beta Was this translation helpful? Give feedback.
-
Proposal V2This is the second version of the previous proposal, taking feedbacks into account and making it more compatibile with the current configuration system. Every rule belongs to a unique group ( NOTE: We could also introduce the supergroup (a set of groups) A rule is associated to a severity level among NOTE: I initially chose A rule belongs to one or several (most likely one) domains. A rule is enabled if and only if:
By default, a set of domains are enabled, and some groups have a default severity level set to NOTE: We should split the current For the time being, rule options are still set directly on the rule. Nursery rules are always prefixed by Let's take an example: {
"linter": {
"enabled": true,
"groups": {
"correctness": "error",
"idiomatic": "warn",
"style": "off",
"nursery": "warn" // Unstable rules
},
"domains": { // enable/disable domains
"base": true,
"jest": true,
"react": false
},
"rules": {
"useConsistentArraySyntax": {
"level": "warn",
"options": {
"syntax": "shorthand"
}
},
"useReactHooks": "group",
"noSuperWithoutExtends": "off",
"useNamingConvention": {
// default level: `group`
"options": {
"enumMemberCase": "Pascal"
}
},
// nursery rule must be prefixed with `nursery/`
"nursery/useAnUnstableRule": "error"
}
}
} |
Beta Was this translation helpful? Give feedback.
-
I just came to the discussions to open a request to not have all rules default to Many editors / plugins of editors have features like "filter diagnostics by severity" or simply highlight diagnostics in different colors, and having everything that comes from biome being an error is restricting the usage of those features. |
Beta Was this translation helpful? Give feedback.
-
A separate idea I had, which might become relevant if we indeed end up including a JS engine in Biome for plugin support, is that a JS engine would also enable us to support import type { BiomeConfiguration } from "$biome-config";
import { config as base } from "../biome.config.ts";
export const config: BiomeConfiguration = {
...base,
formatter: {
...base.formatter,
indentWidth: 4
}
}; It gives more flexibility to users, since they can very selectively choose which parts they want to inherit and which they don’t, and the semantics are unambiguous since they’re defined by JS. |
Beta Was this translation helpful? Give feedback.
-
I like the structure but I think there's still a lot of value in the prefixes/groups. I would propose that the rule names include it as part of the string, e.g. Tangentially related, but I think some of the framework-specific rules (like hook stuff) should be more explicitly grouped under an explicit "react" group. If there's an overlap with other frameworks (e.g. "preact"), it should always be possible to introduce the concept of "aliases", so that there could be something like Something like this might also prevent the need for adding a secondary "grouping" concept like domains and such. "Groups" could serve a double purpose in this way, making it simpler to understand for users, with the (imo very minor) trade-off of potential yet unlikely conflicts that can be very easily detected and communicated to users. |
Beta Was this translation helpful? Give feedback.
-
Building on the v2 proposal and based on my reasoning here (please read first), I want to propose a simplified take. {
"linter": {
"enabled": true,
"presets": {
"base": "recommended",
"react": "recommended",
"jest": "stylistic",
"preact": ["correctness", "stylistic"]
},
"rules": {
"base/useConsistentArraySyntax": "warn",
"base/noSuperWithoutExtends": "off",
"react/useRulesOfHooks": "off",
"experimental/useSortedClasses": {
"level": "warn",
"prefix": "tw-"
}
},
"options": { ... }
}
}
Benefits of this approach:
Other ideas where the added complexity might not be worth it, but still worth considering IMO:
|
Beta Was this translation helpful? Give feedback.
-
This one is very superficial, but how do we feel about renaming the top-level keys using a simpler and more consistent pattern? There's currently a bit of a mix between names that refer to a part of Biome (linter, formatter), names that describe what is being interacted with (vcs, files), and then there's
Another lengthier but still consistent alternative is using gerund forms, e.g. |
Beta Was this translation helpful? Give feedback.
-
As @ematipico suggested, we could use the |
Beta Was this translation helpful? Give feedback.
-
Background
Our database of lint rules is growing, and we have rules that are meant to be used in specific cases, languages, libraries and more. Managing so many rules can become a burden for a user, so Biome should provide more tools for controlling those rules, and the documentation should be more clear.
On top of that, we have a very deep configuration:
Even though we have the JSON schema, it takes a while to turn off a rule.
Goals
category
from the user-facing APIs, but keep them internally;Drawbacks
Remove
rules
and groups from the configurationInternally, we can still map
noBlankTarget
to the group where it belongs because the name of the rules are unique. Still, thenursery
group should be kept, to make it harder for user to opt-in. Reason? Users needs to be aware that they are using rules that are a work in progress.Additionally, we will change our diagnostic categories as a result. Although the nursery rules will keep the
nursery/
group in the category name:linter.ruleSets
Introduction of
ruleSets
. A new option that will allow users to pull rules that belong to different "concepts". For example a user could pull (turn on), rules that belong to our recommended rules, accessibility rules, JSX rules, react hook rules, rules around testing and rules specific to TS projects.:This will replace
linter.rules.recommended
andlint.rules.all
by providing the same functionality:Important
Having rules sets defined as an object will allow to opt in or opt out.
With this strategy, we also drop the incompatibility with this rule sets, meaning that
"all"
will take over every existing rule sets. We leave the decision to the user and ignore that they decide to do.Rules can belong to multiple rule sets. For example, the rule
noBlankTarget
can be long to therecommended
rule set and thea11y
rule set.Rule sets will be part of the metadata of a rule. This will allow us to know in advance this information. With this information, we can create a more grain fined documentation of our rules.
project
A new top level configuration to better configure the project. In this new configuration, biome can enable more optionated features. For example, we can set a kind of project like
"react"
and Biome will enable some rule sets as a result:jsx
,recommended
,test
andreactHooks
:One could also add
"tailwind"
, and Biome will add additional formatting rules for aroundclassName
in JSX:Beta Was this translation helpful? Give feedback.
All reactions