Skip to content

Commit

Permalink
refactor: style recommendation and new recommended severity (#4730)
Browse files Browse the repository at this point in the history
  • Loading branch information
ematipico authored Dec 13, 2024
1 parent 0a9d85a commit a478377
Show file tree
Hide file tree
Showing 90 changed files with 974 additions and 1,755 deletions.
35 changes: 35 additions & 0 deletions .changeset/enable_rule_with_default_severity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
cli: minor
---

# Enable rule with default severity

You can now enable lint rules using the default severity suggested by Biome using the new variant `"on"`, when enabling a rule.

For example, the default severity of the rule `style.noVar` is `error`, so you would use `"on"`, and then linting a code that uses `var`, will result in an error:

```json
{
"linter": {
"recommended": false,
"rules": {
"style": {
"noVar": "on"
}
}
}
}
```

```js
// main.js
var name = "tobias"
```

The command `biome lint main.js` will result in an error due to the default severity assigned to `noVar`.

Refer to the documentation page of each rule to know their suggested diagnostic severity, or use the command `biome explain <RULE_NAME>`:

```shell
biome explain noVar
```
33 changes: 33 additions & 0 deletions .changeset/style_rules_arent_recommended_anymore_.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
cli: major
---

# `style` rules aren't recommended anymore

Linting rules that belong to the group `style` aren't recommended anymore. Here's the list of rules that aren't recommended anymore:

- `useNumberNamespace`
- `noNonnullAssertion`
- `useAsConstAssertion`
- `noParameterAssign`
- `noInferrableTypes`
- `useNodejsImportProtocol`
- `useExportType`
- `useDefaultParameterLast`
- `noUnusedTemplateLiteral`
- `useExponentiationOperator`
- `useEnumInitializers`
- `useShorthandFunctionType`
- `useLiteralEnumMembers`
- `noVar`
- `noUselessElse`
- `useNumericLiterals`
- `noCommaOperator`
- `useConst`
- `noArguments`
- `useSelfClosingElements`
- `useImportType`
- `useTemplate`
- `useSingleVarDeclarator`
- `useWhile`
- `use_while`
3 changes: 2 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
"rules": {
"recommended": true,
"style": {
"noNonNullAssertion": "off"
"noNonNullAssertion": "off",
"noVar": "on"
}
}
},
Expand Down
182 changes: 166 additions & 16 deletions crates/biome_analyze/src/rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
Phase, Phases, Queryable, SourceActionKind, SuppressionAction, SuppressionCommentEmitterPayload,
};
use biome_console::fmt::{Display, Formatter};
use biome_console::{markup, MarkupBuf};
use biome_console::{markup, MarkupBuf, Padding};
use biome_diagnostics::advice::CodeSuggestionAdvice;
use biome_diagnostics::location::AsSpan;
use biome_diagnostics::{
Expand Down Expand Up @@ -47,6 +47,155 @@ pub struct RuleMetadata {
pub domains: &'static [RuleDomain],
}

impl biome_console::fmt::Display for RuleMetadata {
fn fmt(&self, fmt: &mut Formatter) -> std::io::Result<()> {
fmt.write_markup(markup! {
<Emphasis>"Summary"</Emphasis>
})?;
fmt.write_str("\n")?;
fmt.write_str("\n")?;

fmt.write_markup(markup! {
"- Name: "<Emphasis>{self.name}</Emphasis>
})?;
fmt.write_str("\n")?;
match self.fix_kind {
FixKind::None => {
fmt.write_markup(markup! {
"- No fix available."
})?;
}
kind => {
fmt.write_markup(markup! {
"- Fix: "<Emphasis>{kind}</Emphasis>
})?;
}
}
fmt.write_str("\n")?;

fmt.write_markup(markup! {
"- Default severity: "<Emphasis>{self.severity}</Emphasis>
})?;
fmt.write_str("\n")?;

fmt.write_markup(markup! {
"- Available from version: "<Emphasis>{self.version}</Emphasis>
})?;
fmt.write_str("\n")?;

if self.domains.is_empty() && self.recommended {
fmt.write_markup(markup! {
"- This rule is not recommended"
})?;
}

let domains = DisplayDomains(self.domains, self.recommended);

fmt.write_str("\n")?;

fmt.write_markup(markup!({ domains }))?;

fmt.write_str("\n")?;

fmt.write_markup(markup! {
<Emphasis>"Description"</Emphasis>
})?;
fmt.write_str("\n")?;
fmt.write_str("\n")?;

for line in self.docs.lines() {
if let Some((_, remainder)) = line.split_once("## ") {
fmt.write_markup(markup! {
<Emphasis>{remainder.trim_start()}</Emphasis>
})?;
} else if let Some((_, remainder)) = line.split_once("### ") {
fmt.write_markup(markup! {
<Emphasis>{remainder.trim_start()}</Emphasis>
})?;
} else {
fmt.write_str(line)?;
}

fmt.write_str("\n")?;
}

Ok(())
}
}

struct DisplayDomains(&'static [RuleDomain], bool);

impl Display for DisplayDomains {
fn fmt(&self, fmt: &mut Formatter) -> std::io::Result<()> {
let domains = self.0;
let recommended = self.1;

if domains.is_empty() {
return Ok(());
}

fmt.write_markup(markup!(
<Emphasis>"Domains"</Emphasis>
))?;
fmt.write_str("\n")?;
fmt.write_str("\n")?;

for domain in domains {
let dependencies = domain.manifest_dependencies();

fmt.write_markup(markup! {
"- Name: "<Emphasis>{domain}</Emphasis>
})?;
fmt.write_str("\n")?;

if recommended {
fmt.write_markup(markup! {
"- The rule is recommended for this domain"
})?;
fmt.write_str("\n")?;
}

if !dependencies.is_empty() {
fmt.write_markup(markup! {
"- The rule is enabled when one of these dependencies are detected:"
})?;
fmt.write_str("\n")?;
let padding = Padding::new(2);
for (index, (dep, range)) in dependencies.iter().enumerate() {
fmt.write_markup(
markup! { {padding}"- "<Emphasis>{dep}"@"{range}</Emphasis> },
)?;
if index + 1 < dependencies.len() {
fmt.write_str("\n")?;
}
}
fmt.write_str("\n")?;
}

let globals = domain.globals();

if !globals.is_empty() {
fmt.write_markup(markup! {
"- The rule adds the following globals: "
})?;
fmt.write_str("\n")?;

let padding = Padding::new(2);
for (index, global) in globals.iter().enumerate() {
fmt.write_markup(markup! { {padding}"- "<Emphasis>{global}</Emphasis> })?;
if index + 1 < globals.len() {
fmt.write_str("\n")?;
}
}
fmt.write_str("\n")?;
}
fmt.write_str("\n")?;
}

Ok(())
}
}

#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
#[cfg_attr(
feature = "serde",
Expand All @@ -73,9 +222,9 @@ pub enum FixKind {
impl Display for FixKind {
fn fmt(&self, fmt: &mut biome_console::fmt::Formatter) -> std::io::Result<()> {
match self {
FixKind::None => fmt.write_str("None"),
FixKind::Safe => fmt.write_str("Safe"),
FixKind::Unsafe => fmt.write_str("Unsafe"),
FixKind::None => fmt.write_markup(markup!("none")),
FixKind::Safe => fmt.write_markup(markup!(<Success>"safe"</Success>)),
FixKind::Unsafe => fmt.write_markup(markup!(<Warn>"unsafe"</Warn>)),
}
}
}
Expand Down Expand Up @@ -338,6 +487,18 @@ pub enum RuleDomain {
Next,
}

impl Display for RuleDomain {
fn fmt(&self, fmt: &mut Formatter) -> std::io::Result<()> {
// use lower case naming, it needs to match the name of the configuration
match self {
RuleDomain::React => fmt.write_str("react"),
RuleDomain::Test => fmt.write_str("test"),
RuleDomain::Solid => fmt.write_str("solid"),
RuleDomain::Next => fmt.write_str("next"),
}
}
}

impl RuleDomain {
/// If the project has one of these dependencies, the domain will be automatically enabled, unless it's explicitly disabled by the configuration.
///
Expand All @@ -352,7 +513,7 @@ impl RuleDomain {
&("vitest", ">=1.0.0"),
],
RuleDomain::Solid => &[&("solid", ">=1.0.0")],
RuleDomain::Next => &[&("react", ">=16.0.0"), &("next", ">=14.0.0")],
RuleDomain::Next => &[&("next", ">=14.0.0")],
}
}

Expand All @@ -378,17 +539,6 @@ impl RuleDomain {
}
}

impl Display for RuleDomain {
fn fmt(&self, fmt: &mut Formatter) -> std::io::Result<()> {
match self {
RuleDomain::React => fmt.write_str("React"),
RuleDomain::Test => fmt.write_str("Test"),
RuleDomain::Solid => fmt.write_str("Solid"),
RuleDomain::Next => fmt.write_str("Next.js"),
}
}
}

impl RuleMetadata {
pub const fn new(
version: &'static str,
Expand Down
31 changes: 2 additions & 29 deletions crates/biome_cli/src/commands/explain.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use biome_analyze::{FixKind, RuleMetadata};
use biome_analyze::RuleMetadata;
use biome_console::{markup, ConsoleExt};
use biome_flags::biome_env;
use biome_service::documentation::Doc;
Expand All @@ -8,34 +8,7 @@ use crate::{CliDiagnostic, CliSession};

fn print_rule(session: CliSession, metadata: &RuleMetadata) {
session.app.console.log(markup! {
"# "{metadata.name}"\n"
});

match metadata.fix_kind {
FixKind::None => {
session.app.console.log(markup! {
"No fix available.\n"
});
}
kind => {
session.app.console.log(markup! {
"Fix is "{kind}".\n"
});
}
}

let docs = metadata
.docs
.lines()
.map(|line| line.trim_start())
.collect::<Vec<_>>()
.join("\n");

session.app.console.log(markup! {
"This rule is "{if metadata.recommended {"recommended."} else {"not recommended."}}
"\n\n"
"# Description\n"
{docs}
{metadata}
});
}

Expand Down
Loading

0 comments on commit a478377

Please sign in to comment.