mirror of
https://github.com/biomejs/biome.git
synced 2025-12-23 08:21:13 +00:00
feat(lint): add useBiomeIgnoreFolder and noBiomeFirstException (#7159)
Co-authored-by: dyc3 <1808807+dyc3@users.noreply.github.com> Co-authored-by: siketyan <12772118+siketyan@users.noreply.github.com>
This commit is contained in:
parent
a653a0fb3f
commit
df3afdf0e2
25 changed files with 918 additions and 203 deletions
21
.changeset/floppy-sloths-visit.md
Normal file
21
.changeset/floppy-sloths-visit.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
"@biomejs/biome": minor
|
||||
---
|
||||
|
||||
Added the new rule `useBiomeIgnoreFolder`. Since v2.2, Biome correctly prevents the indexing and crawling of folders.
|
||||
|
||||
However, the correct pattern has changed. This rule attempts to detect incorrect usage, and promote the new pattern:
|
||||
|
||||
```diff
|
||||
// biome.json
|
||||
{
|
||||
"files": {
|
||||
"includes": [
|
||||
- "!dist/**",
|
||||
- "!**/fixtures/**",
|
||||
+ "!dist",
|
||||
+ "!**/fixtures",
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
16
.changeset/proud-olives-exist.md
Normal file
16
.changeset/proud-olives-exist.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
"@biomejs/biome": minor
|
||||
---
|
||||
|
||||
Added the new rule `noBiomeFirstException`. This rule prevents the incorrect usage of patterns inside `files.includes`.
|
||||
|
||||
This rule catches if the first element of the array contains `!`. This mistake will cause Biome to analyze no files:
|
||||
|
||||
```json5
|
||||
// biome.json
|
||||
{
|
||||
"files": {
|
||||
"includes": ["!dist/**"] // this is an error
|
||||
}
|
||||
}
|
||||
```
|
||||
10
biome.json
10
biome.json
|
|
@ -25,13 +25,13 @@
|
|||
"**/packages/tailwindcss-config-analyzer/**",
|
||||
"**/benchmark/**",
|
||||
"scripts/**",
|
||||
"!**/crates/**",
|
||||
"!**/dist/**",
|
||||
"!**/crates",
|
||||
"!**/dist",
|
||||
"!**/packages/@biomejs/backend-jsonrpc/src/workspace.ts",
|
||||
"!**/__snapshots__",
|
||||
"!**/undefined/**",
|
||||
"!**/benchmark/target/**",
|
||||
"!**/benches/**"
|
||||
"!**/undefined",
|
||||
"!**/benchmark/target",
|
||||
"!**/benches"
|
||||
],
|
||||
"experimentalScannerIgnores": [
|
||||
".cargo",
|
||||
|
|
|
|||
430
crates/biome_configuration/src/analyzer/linter/rules.rs
generated
430
crates/biome_configuration/src/analyzer/linter/rules.rs
generated
File diff suppressed because one or more lines are too long
|
|
@ -161,7 +161,6 @@ define_categories! {
|
|||
"lint/correctness/useValidForDirection": "https://biomejs.dev/linter/rules/use-valid-for-direction",
|
||||
"lint/correctness/useValidTypeof": "https://biomejs.dev/linter/rules/use-valid-typeof",
|
||||
"lint/correctness/useYield": "https://biomejs.dev/linter/rules/use-yield",
|
||||
"lint/nursery/colorNoInvalidHex": "https://biomejs.dev/linter/rules/color-no-invalid-hex",
|
||||
"lint/nursery/noNextAsyncClientComponent": "https://biomejs.dev/linter/rules/no-next-async-client-component",
|
||||
"lint/nursery/noColorInvalidHex": "https://biomejs.dev/linter/rules/no-color-invalid-hex",
|
||||
"lint/nursery/noFloatingPromises": "https://biomejs.dev/linter/rules/no-floating-promises",
|
||||
|
|
@ -178,9 +177,9 @@ define_categories! {
|
|||
"lint/nursery/noUnwantedPolyfillio": "https://biomejs.dev/linter/rules/no-unwanted-polyfillio",
|
||||
"lint/nursery/noUselessBackrefInRegex": "https://biomejs.dev/linter/rules/no-useless-backref-in-regex",
|
||||
"lint/nursery/noUselessUndefined": "https://biomejs.dev/linter/rules/no-useless-undefined",
|
||||
"lint/nursery/noVueDataObjectDeclaration": "https://biomejs.dev/linter/rules/no-vue-data-object-declaration",
|
||||
"lint/nursery/noVueReservedKeys": "https://biomejs.dev/linter/rules/no-vue-reserved-keys",
|
||||
"lint/nursery/noVueReservedProps": "https://biomejs.dev/linter/rules/no-vue-reserved-props",
|
||||
"lint/nursery/noVueDataObjectDeclaration": "https://biomejs.dev/linter/rules/no-vue-data-object-declaration",
|
||||
"lint/nursery/useAnchorHref": "https://biomejs.dev/linter/rules/use-anchor-href",
|
||||
"lint/nursery/useBiomeSuppressionComment": "https://biomejs.dev/linter/rules/use-biome-suppression-comment",
|
||||
"lint/nursery/useConsistentObjectDefinition": "https://biomejs.dev/linter/rules/use-consistent-object-definition",
|
||||
|
|
@ -289,6 +288,7 @@ define_categories! {
|
|||
"lint/suspicious/noArrayIndexKey": "https://biomejs.dev/linter/rules/no-array-index-key",
|
||||
"lint/suspicious/noAssignInExpressions": "https://biomejs.dev/linter/rules/no-assign-in-expressions",
|
||||
"lint/suspicious/noAsyncPromiseExecutor": "https://biomejs.dev/linter/rules/no-async-promise-executor",
|
||||
"lint/suspicious/noBiomeFirstException": "https://biomejs.dev/linter/rules/no-biome-first-exception",
|
||||
"lint/suspicious/noBitwiseOperators": "https://biomejs.dev/linter/rules/no-bitwise-operators",
|
||||
"lint/suspicious/noCatchAssign": "https://biomejs.dev/linter/rules/no-catch-assign",
|
||||
"lint/suspicious/noClassAssign": "https://biomejs.dev/linter/rules/no-class-assign",
|
||||
|
|
@ -365,6 +365,7 @@ define_categories! {
|
|||
"lint/suspicious/noWith": "https://biomejs.dev/linter/rules/no-with",
|
||||
"lint/suspicious/useAdjacentOverloadSignatures": "https://biomejs.dev/linter/rules/use-adjacent-overload-signatures",
|
||||
"lint/suspicious/useAwait": "https://biomejs.dev/linter/rules/use-await",
|
||||
"lint/suspicious/useBiomeIgnoreFolder": "https://biomejs.dev/linter/rules/use-biome-ignore-folder",
|
||||
"lint/suspicious/useIterableCallbackReturn": "https://biomejs.dev/linter/rules/use-iterable-callback-return",
|
||||
"lint/suspicious/useDefaultSwitchClauseLast": "https://biomejs.dev/linter/rules/use-default-switch-clause-last",
|
||||
"lint/suspicious/useErrorMessage": "https://biomejs.dev/linter/rules/use-error-message",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
//! Generated file, do not edit by hand, see `xtask/codegen`
|
||||
|
||||
use biome_analyze::declare_lint_group;
|
||||
pub mod no_biome_first_exception;
|
||||
pub mod no_duplicate_object_keys;
|
||||
pub mod no_quickfix_biome;
|
||||
declare_lint_group! { pub Suspicious { name : "suspicious" , rules : [self :: no_duplicate_object_keys :: NoDuplicateObjectKeys , self :: no_quickfix_biome :: NoQuickfixBiome ,] } }
|
||||
pub mod use_biome_ignore_folder;
|
||||
declare_lint_group! { pub Suspicious { name : "suspicious" , rules : [self :: no_biome_first_exception :: NoBiomeFirstException , self :: no_duplicate_object_keys :: NoDuplicateObjectKeys , self :: no_quickfix_biome :: NoQuickfixBiome , self :: use_biome_ignore_folder :: UseBiomeIgnoreFolder ,] } }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,145 @@
|
|||
use crate::JsonRuleAction;
|
||||
use crate::utils::matches_parent_object;
|
||||
use biome_analyze::{Ast, FixKind, Rule, RuleDiagnostic, context::RuleContext, declare_lint_rule};
|
||||
use biome_console::markup;
|
||||
use biome_diagnostics::Severity;
|
||||
use biome_json_factory::make::{
|
||||
json_array_element_list, json_string_literal, json_string_value, token,
|
||||
};
|
||||
use biome_json_syntax::{AnyJsonValue, JsonMember, JsonStringValue, T};
|
||||
use biome_rowan::{AstNode, AstSeparatedList, BatchMutationExt};
|
||||
use biome_rule_options::no_biome_first_exception::NoBiomeFirstExceptionOptions;
|
||||
|
||||
declare_lint_rule! {
|
||||
/// Prevents the use of the `!` pattern in the first position of `files.includes` in the configuration file.
|
||||
///
|
||||
/// If the first pattern of `files.includes` starts with the leading `!`, Biome won't have any file to crawl. Generally,
|
||||
/// it is a good practice to declare the files/folders to include first, and then the files/folder to ignore.
|
||||
///
|
||||
/// Check the [official documentation](https://biomejs.dev/guides/configure-biome/#exclude-files-via-configuration) for more examples.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ### Invalid
|
||||
///
|
||||
/// ```json,ignore
|
||||
/// {
|
||||
/// "files": {
|
||||
/// "includes": ["!dist"]
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ### Valid
|
||||
///
|
||||
/// ```json,ignore
|
||||
/// {
|
||||
/// "files": {
|
||||
/// "includes": ["src/**", "!dist"]
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub NoBiomeFirstException {
|
||||
version: "next",
|
||||
name: "noBiomeFirstException",
|
||||
language: "json",
|
||||
recommended: true,
|
||||
severity: Severity::Error,
|
||||
fix_kind: FixKind::Safe,
|
||||
}
|
||||
}
|
||||
|
||||
impl Rule for NoBiomeFirstException {
|
||||
type Query = Ast<JsonMember>;
|
||||
type State = JsonStringValue;
|
||||
type Signals = Option<Self::State>;
|
||||
type Options = NoBiomeFirstExceptionOptions;
|
||||
|
||||
fn run(ctx: &RuleContext<Self>) -> Option<Self::State> {
|
||||
let node = ctx.query();
|
||||
let file_path = ctx.file_path();
|
||||
// we use ends_with so it works only during testing
|
||||
if !file_path
|
||||
.file_name()
|
||||
.is_some_and(|file_name| file_name.ends_with("biome.json"))
|
||||
&& !file_path
|
||||
.file_name()
|
||||
.is_some_and(|file_name| file_name.ends_with("biome.jsonc"))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let name = node.name().ok()?;
|
||||
|
||||
if name.inner_string_text().ok()?.text() != "includes" {
|
||||
return None;
|
||||
}
|
||||
|
||||
if !matches_parent_object(node, "files") {
|
||||
return None;
|
||||
}
|
||||
|
||||
let value = node.value().ok()?;
|
||||
let value = value.as_json_array_value()?;
|
||||
if let Some(element) = value.elements().first() {
|
||||
let element = element.ok()?;
|
||||
let string_value = element.as_json_string_value()?;
|
||||
|
||||
if string_value
|
||||
.inner_string_text()
|
||||
.ok()?
|
||||
.text()
|
||||
.starts_with('!')
|
||||
{
|
||||
return Some(string_value.clone());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn diagnostic(_ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> {
|
||||
Some(
|
||||
RuleDiagnostic::new(
|
||||
rule_category!(),
|
||||
state.range(),
|
||||
markup! {
|
||||
"Incorrect usage of the exception detected."
|
||||
},
|
||||
)
|
||||
.note(markup! {
|
||||
"Having a pattern that starts with `!` as first item will cause Biome to match no files."
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
fn action(ctx: &RuleContext<Self>, _state: &Self::State) -> Option<JsonRuleAction> {
|
||||
let mut mutation = ctx.root().begin();
|
||||
let old_list = ctx.query().value().ok()?.as_json_array_value()?.elements();
|
||||
let list = old_list.iter().flatten().collect::<Vec<_>>();
|
||||
let mut new_list = vec![AnyJsonValue::JsonStringValue(json_string_value(
|
||||
json_string_literal("**"),
|
||||
))];
|
||||
|
||||
new_list.extend(list);
|
||||
let mut separators = vec![];
|
||||
|
||||
for _ in 0..new_list.len() - 1 {
|
||||
separators.push(token(T![,]))
|
||||
}
|
||||
|
||||
let new_list = json_array_element_list(new_list, separators);
|
||||
|
||||
mutation.replace_node(old_list, new_list);
|
||||
|
||||
Some(JsonRuleAction::new(
|
||||
ctx.metadata().action_category(ctx.category(), ctx.group()),
|
||||
ctx.metadata().applicability(),
|
||||
markup! {
|
||||
"Add the patter "<Emphasis>"**"</Emphasis>" at the beginning of the list."
|
||||
},
|
||||
mutation,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
use crate::JsonRuleAction;
|
||||
use crate::utils::matches_parent_object;
|
||||
use biome_analyze::{Ast, FixKind, Rule, RuleDiagnostic, context::RuleContext, declare_lint_rule};
|
||||
use biome_console::markup;
|
||||
use biome_diagnostics::Severity;
|
||||
use biome_json_factory::make::{json_string_literal, json_string_value};
|
||||
use biome_json_syntax::{JsonMember, JsonStringValue};
|
||||
use biome_rowan::{AstNode, AstSeparatedList, BatchMutationExt};
|
||||
use biome_rule_options::use_biome_ignore_folder::UseBiomeIgnoreFolderOptions;
|
||||
|
||||
declare_lint_rule! {
|
||||
/// Promotes the correct usage for ignoring folders in the configuration file.
|
||||
///
|
||||
/// Starting Biome v2.2, ignoring folders doesn't require the use of the trailing `/**`.
|
||||
/// When using the pattern `/**`, you tell Biome to ignore **all files** inside a folder, but the folder is still crawled. This pattern
|
||||
/// can lead to poor performance, especially if the folder contains many files.
|
||||
///
|
||||
/// If the intention is to ignore specific files inside a folder, the trailing pattern `/**` shouldn't be used.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ### Invalid
|
||||
///
|
||||
/// ```json,ignore
|
||||
/// {
|
||||
/// "files": {
|
||||
/// "includes": ["**", "!dist/**", "!**/dist/**"]
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ### Valid
|
||||
///
|
||||
/// ```json,ignore
|
||||
/// {
|
||||
/// "files": {
|
||||
/// "includes": ["**", "!dist", "!**/dist"]
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub UseBiomeIgnoreFolder {
|
||||
version: "next",
|
||||
name: "useBiomeIgnoreFolder",
|
||||
language: "json",
|
||||
recommended: true,
|
||||
fix_kind: FixKind::Safe,
|
||||
severity: Severity::Warning,
|
||||
}
|
||||
}
|
||||
|
||||
impl Rule for UseBiomeIgnoreFolder {
|
||||
type Query = Ast<JsonMember>;
|
||||
type State = JsonStringValue;
|
||||
type Signals = Vec<Self::State>;
|
||||
type Options = UseBiomeIgnoreFolderOptions;
|
||||
|
||||
fn run(ctx: &RuleContext<Self>) -> Vec<Self::State> {
|
||||
let node = ctx.query();
|
||||
let name = node.name().ok();
|
||||
let mut values = vec![];
|
||||
let file_path = ctx.file_path();
|
||||
// we use ends_with so it works only during testing
|
||||
if !file_path
|
||||
.file_name()
|
||||
.is_some_and(|file_name| file_name.ends_with("biome.json"))
|
||||
&& !file_path
|
||||
.file_name()
|
||||
.is_some_and(|file_name| file_name.ends_with("biome.jsonc"))
|
||||
{
|
||||
return values;
|
||||
}
|
||||
|
||||
if name.is_some_and(|name| {
|
||||
name.inner_string_text()
|
||||
.ok()
|
||||
.is_some_and(|text| text.text() != "includes")
|
||||
}) {
|
||||
return values;
|
||||
}
|
||||
|
||||
if !matches_parent_object(node, "files") {
|
||||
return values;
|
||||
}
|
||||
|
||||
if let Ok(value) = node.value()
|
||||
&& let Some(value) = value.as_json_array_value()
|
||||
{
|
||||
for array_value in value.elements().iter().flatten() {
|
||||
if let Some(string_value) = array_value.as_json_string_value()
|
||||
&& let Ok(inner_value) = string_value.inner_string_text()
|
||||
&& inner_value.text().starts_with('!')
|
||||
&& inner_value.text().ends_with("/**")
|
||||
{
|
||||
values.push(string_value.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
values
|
||||
}
|
||||
|
||||
fn diagnostic(_ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> {
|
||||
Some(
|
||||
RuleDiagnostic::new(
|
||||
rule_category!(),
|
||||
state.range(),
|
||||
markup! {
|
||||
"Incorrect usage of ignore a folder found."
|
||||
},
|
||||
)
|
||||
.note(markup! {
|
||||
"Since version 2.2.0, ignoring folders doesn't require the use the trailing "<Emphasis>"/**"</Emphasis>". This is a bug that affects version prior v2.2.0."
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
fn action(ctx: &RuleContext<Self>, state: &Self::State) -> Option<JsonRuleAction> {
|
||||
let mut mutation = ctx.root().begin();
|
||||
let former_pattern = state.inner_string_text().ok()?.text().to_string();
|
||||
let new_pattern = former_pattern
|
||||
.strip_suffix("/**")
|
||||
.unwrap_or(&former_pattern);
|
||||
let new_value = json_string_value(json_string_literal(new_pattern));
|
||||
|
||||
mutation.replace_node(state.clone(), new_value);
|
||||
|
||||
Some(JsonRuleAction::new(
|
||||
ctx.metadata().action_category(ctx.category(), ctx.group()),
|
||||
ctx.metadata().applicability(),
|
||||
markup! {
|
||||
"If you want to ignore a folder, use the following pattern instead: "<Emphasis>{new_pattern}</Emphasis>"."
|
||||
},
|
||||
mutation,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
@ -46,3 +46,14 @@ pub fn matches_path(optional_node: Option<&JsonMemberName>, path: &[&str]) -> bo
|
|||
|
||||
matches_path(optional_parent_node.as_ref(), &path[..path.len() - 1])
|
||||
}
|
||||
|
||||
/// Finds the first ancestor [JsonMember], and returns [true] if it's name matches the given input
|
||||
pub(crate) fn matches_parent_object(node: &JsonMember, name: &str) -> bool {
|
||||
node.syntax()
|
||||
.ancestors()
|
||||
.skip(1)
|
||||
.find_map(JsonMember::cast)
|
||||
.and_then(|member| member.name().ok())
|
||||
.and_then(|member| member.inner_string_text().ok())
|
||||
.is_some_and(|text| text.text() == name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
// should generate diagnostics
|
||||
{
|
||||
"files": {
|
||||
"includes": [
|
||||
"!dist/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
source: crates/biome_json_analyze/tests/spec_tests.rs
|
||||
expression: invalid.biome.jsonc
|
||||
---
|
||||
# Input
|
||||
```jsonc
|
||||
// should generate diagnostics
|
||||
{
|
||||
"files": {
|
||||
"includes": [
|
||||
"!dist/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
```
|
||||
invalid.biome.jsonc:5:4 lint/suspicious/noBiomeFirstException FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
× Incorrect usage of the exception detected.
|
||||
|
||||
3 │ "files": {
|
||||
4 │ "includes": [
|
||||
> 5 │ "!dist/**"
|
||||
│ ^^^^^^^^^^
|
||||
6 │ ]
|
||||
7 │ }
|
||||
|
||||
i Having a pattern that starts with `!` as first item will cause Biome to match no files.
|
||||
|
||||
i Safe fix: Add the patter ** at the beginning of the list.
|
||||
|
||||
3 3 │ "files": {
|
||||
4 4 │ "includes": [
|
||||
5 │ - → → → "!dist/**"
|
||||
5 │ + → → → "**",
|
||||
6 │ + → → → "!dist/**"
|
||||
6 7 │ ]
|
||||
7 8 │ }
|
||||
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// should not generate diagnostics
|
||||
{
|
||||
"files": {
|
||||
"includes": [
|
||||
"**",
|
||||
"!**/dist"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
source: crates/biome_json_analyze/tests/spec_tests.rs
|
||||
expression: valid.biome.jsonc
|
||||
---
|
||||
# Input
|
||||
```jsonc
|
||||
// should not generate diagnostics
|
||||
{
|
||||
"files": {
|
||||
"includes": [
|
||||
"**",
|
||||
"!**/dist"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// should generate diagnostics
|
||||
{
|
||||
"files": {
|
||||
"includes": [
|
||||
"**",
|
||||
"!dist/**",
|
||||
"!**/dist/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
source: crates/biome_json_analyze/tests/spec_tests.rs
|
||||
expression: invalid.biome.jsonc
|
||||
---
|
||||
# Input
|
||||
```jsonc
|
||||
// should generate diagnostics
|
||||
{
|
||||
"files": {
|
||||
"includes": [
|
||||
"**",
|
||||
"!dist/**",
|
||||
"!**/dist/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
```
|
||||
invalid.biome.jsonc:6:7 lint/suspicious/useBiomeIgnoreFolder FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
! Incorrect usage of ignore a folder found.
|
||||
|
||||
4 │ "includes": [
|
||||
5 │ "**",
|
||||
> 6 │ "!dist/**",
|
||||
│ ^^^^^^^^^^
|
||||
7 │ "!**/dist/**"
|
||||
8 │ ]
|
||||
|
||||
i Since version 2.2.0, ignoring folders doesn't require the use the trailing /**. This is a bug that affects version prior v2.2.0.
|
||||
|
||||
i Safe fix: If you want to ignore a folder, use the following pattern instead: !dist.
|
||||
|
||||
6 │ ······"!dist/**",
|
||||
│ ---
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
invalid.biome.jsonc:7:7 lint/suspicious/useBiomeIgnoreFolder FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
! Incorrect usage of ignore a folder found.
|
||||
|
||||
5 │ "**",
|
||||
6 │ "!dist/**",
|
||||
> 7 │ "!**/dist/**"
|
||||
│ ^^^^^^^^^^^^^
|
||||
8 │ ]
|
||||
9 │ }
|
||||
|
||||
i Since version 2.2.0, ignoring folders doesn't require the use the trailing /**. This is a bug that affects version prior v2.2.0.
|
||||
|
||||
i Safe fix: If you want to ignore a folder, use the following pattern instead: !**/dist.
|
||||
|
||||
7 │ ······"!**/dist/**"
|
||||
│ ---
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// should not generate diagnostics
|
||||
{
|
||||
"files": {
|
||||
"includes": [
|
||||
"**",
|
||||
"!dist",
|
||||
"!**/dist"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
source: crates/biome_json_analyze/tests/spec_tests.rs
|
||||
expression: valid.biome.jsonc
|
||||
---
|
||||
# Input
|
||||
```jsonc
|
||||
// should not generate diagnostics
|
||||
{
|
||||
"files": {
|
||||
"includes": [
|
||||
"**",
|
||||
"!dist",
|
||||
"!**/dist"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// should not generate diagnostics
|
||||
{
|
||||
"overrides": [
|
||||
{
|
||||
"includes": [
|
||||
"!dist"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
source: crates/biome_json_analyze/tests/spec_tests.rs
|
||||
expression: valid_overrides.biome.jsonc
|
||||
---
|
||||
# Input
|
||||
```jsonc
|
||||
// should not generate diagnostics
|
||||
{
|
||||
"overrides": [
|
||||
{
|
||||
"includes": [
|
||||
"!dist"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
|
@ -17,6 +17,7 @@ pub mod no_autofocus;
|
|||
pub mod no_await_in_loops;
|
||||
pub mod no_banned_types;
|
||||
pub mod no_barrel_file;
|
||||
pub mod no_biome_first_exception;
|
||||
pub mod no_bitwise_operators;
|
||||
pub mod no_blank_target;
|
||||
pub mod no_catch_assign;
|
||||
|
|
@ -247,6 +248,7 @@ pub mod use_arrow_function;
|
|||
pub mod use_as_const_assertion;
|
||||
pub mod use_at_index;
|
||||
pub mod use_await;
|
||||
pub mod use_biome_ignore_folder;
|
||||
pub mod use_block_statements;
|
||||
pub mod use_button_type;
|
||||
pub mod use_collapsed_else_if;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
use biome_deserialize_macros::Deserializable;
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[derive(Default, Clone, Debug, Deserialize, Deserializable, Eq, PartialEq, Serialize)]
|
||||
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields, default)]
|
||||
pub struct NoBiomeFirstExceptionOptions {}
|
||||
6
crates/biome_rule_options/src/use_biome_ignore_folder.rs
Normal file
6
crates/biome_rule_options/src/use_biome_ignore_folder.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
use biome_deserialize_macros::Deserializable;
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[derive(Default, Clone, Debug, Deserialize, Deserializable, Eq, PartialEq, Serialize)]
|
||||
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields, default)]
|
||||
pub struct UseBiomeIgnoreFolderOptions {}
|
||||
49
packages/@biomejs/backend-jsonrpc/src/workspace.ts
generated
49
packages/@biomejs/backend-jsonrpc/src/workspace.ts
generated
|
|
@ -2121,6 +2121,10 @@ export interface Suspicious {
|
|||
* Disallows using an async function as a Promise executor.
|
||||
*/
|
||||
noAsyncPromiseExecutor?: RuleConfiguration_for_NoAsyncPromiseExecutorOptions;
|
||||
/**
|
||||
* Prevents the use of the ! pattern in the first position of files.includes in the configuration file.
|
||||
*/
|
||||
noBiomeFirstException?: RuleFixConfiguration_for_NoBiomeFirstExceptionOptions;
|
||||
/**
|
||||
* Disallow bitwise operators.
|
||||
*/
|
||||
|
|
@ -2429,6 +2433,10 @@ export interface Suspicious {
|
|||
* Ensure async functions utilize await.
|
||||
*/
|
||||
useAwait?: RuleConfiguration_for_UseAwaitOptions;
|
||||
/**
|
||||
* Promotes the correct usage for ignoring folders in the configuration file.
|
||||
*/
|
||||
useBiomeIgnoreFolder?: RuleFixConfiguration_for_UseBiomeIgnoreFolderOptions;
|
||||
/**
|
||||
* Enforce default clauses in switch statements to be last
|
||||
*/
|
||||
|
|
@ -3295,6 +3303,9 @@ export type RuleConfiguration_for_NoAssignInExpressionsOptions =
|
|||
export type RuleConfiguration_for_NoAsyncPromiseExecutorOptions =
|
||||
| RulePlainConfiguration
|
||||
| RuleWithOptions_for_NoAsyncPromiseExecutorOptions;
|
||||
export type RuleFixConfiguration_for_NoBiomeFirstExceptionOptions =
|
||||
| RulePlainConfiguration
|
||||
| RuleWithFixOptions_for_NoBiomeFirstExceptionOptions;
|
||||
export type RuleConfiguration_for_NoBitwiseOperatorsOptions =
|
||||
| RulePlainConfiguration
|
||||
| RuleWithOptions_for_NoBitwiseOperatorsOptions;
|
||||
|
|
@ -3523,6 +3534,9 @@ export type RuleConfiguration_for_UseAdjacentOverloadSignaturesOptions =
|
|||
export type RuleConfiguration_for_UseAwaitOptions =
|
||||
| RulePlainConfiguration
|
||||
| RuleWithOptions_for_UseAwaitOptions;
|
||||
export type RuleFixConfiguration_for_UseBiomeIgnoreFolderOptions =
|
||||
| RulePlainConfiguration
|
||||
| RuleWithFixOptions_for_UseBiomeIgnoreFolderOptions;
|
||||
export type RuleConfiguration_for_UseDefaultSwitchClauseLastOptions =
|
||||
| RulePlainConfiguration
|
||||
| RuleWithOptions_for_UseDefaultSwitchClauseLastOptions;
|
||||
|
|
@ -6664,6 +6678,20 @@ export interface RuleWithOptions_for_NoAsyncPromiseExecutorOptions {
|
|||
*/
|
||||
options: NoAsyncPromiseExecutorOptions;
|
||||
}
|
||||
export interface RuleWithFixOptions_for_NoBiomeFirstExceptionOptions {
|
||||
/**
|
||||
* The kind of the code actions emitted by the rule
|
||||
*/
|
||||
fix?: FixKind;
|
||||
/**
|
||||
* The severity of the emitted diagnostics by the rule
|
||||
*/
|
||||
level: RulePlainConfiguration;
|
||||
/**
|
||||
* Rule's options
|
||||
*/
|
||||
options: NoBiomeFirstExceptionOptions;
|
||||
}
|
||||
export interface RuleWithOptions_for_NoBitwiseOperatorsOptions {
|
||||
/**
|
||||
* The severity of the emitted diagnostics by the rule
|
||||
|
|
@ -7524,6 +7552,20 @@ export interface RuleWithOptions_for_UseAwaitOptions {
|
|||
*/
|
||||
options: UseAwaitOptions;
|
||||
}
|
||||
export interface RuleWithFixOptions_for_UseBiomeIgnoreFolderOptions {
|
||||
/**
|
||||
* The kind of the code actions emitted by the rule
|
||||
*/
|
||||
fix?: FixKind;
|
||||
/**
|
||||
* The severity of the emitted diagnostics by the rule
|
||||
*/
|
||||
level: RulePlainConfiguration;
|
||||
/**
|
||||
* Rule's options
|
||||
*/
|
||||
options: UseBiomeIgnoreFolderOptions;
|
||||
}
|
||||
export interface RuleWithOptions_for_UseDefaultSwitchClauseLastOptions {
|
||||
/**
|
||||
* The severity of the emitted diagnostics by the rule
|
||||
|
|
@ -8160,6 +8202,7 @@ export interface NoApproximativeNumericConstantOptions {}
|
|||
export interface NoArrayIndexKeyOptions {}
|
||||
export interface NoAssignInExpressionsOptions {}
|
||||
export interface NoAsyncPromiseExecutorOptions {}
|
||||
export interface NoBiomeFirstExceptionOptions {}
|
||||
export interface NoBitwiseOperatorsOptions {
|
||||
/**
|
||||
* Allows a list of bitwise operators to be used as exceptions.
|
||||
|
|
@ -8263,6 +8306,7 @@ export interface NoVarOptions {}
|
|||
export interface NoWithOptions {}
|
||||
export interface UseAdjacentOverloadSignaturesOptions {}
|
||||
export interface UseAwaitOptions {}
|
||||
export interface UseBiomeIgnoreFolderOptions {}
|
||||
export interface UseDefaultSwitchClauseLastOptions {}
|
||||
export interface UseErrorMessageOptions {}
|
||||
export interface UseGetterReturnOptions {}
|
||||
|
|
@ -8649,7 +8693,6 @@ export type Category =
|
|||
| "lint/correctness/useValidForDirection"
|
||||
| "lint/correctness/useValidTypeof"
|
||||
| "lint/correctness/useYield"
|
||||
| "lint/nursery/colorNoInvalidHex"
|
||||
| "lint/nursery/noNextAsyncClientComponent"
|
||||
| "lint/nursery/noColorInvalidHex"
|
||||
| "lint/nursery/noFloatingPromises"
|
||||
|
|
@ -8666,9 +8709,9 @@ export type Category =
|
|||
| "lint/nursery/noUnwantedPolyfillio"
|
||||
| "lint/nursery/noUselessBackrefInRegex"
|
||||
| "lint/nursery/noUselessUndefined"
|
||||
| "lint/nursery/noVueDataObjectDeclaration"
|
||||
| "lint/nursery/noVueReservedKeys"
|
||||
| "lint/nursery/noVueReservedProps"
|
||||
| "lint/nursery/noVueDataObjectDeclaration"
|
||||
| "lint/nursery/useAnchorHref"
|
||||
| "lint/nursery/useBiomeSuppressionComment"
|
||||
| "lint/nursery/useConsistentObjectDefinition"
|
||||
|
|
@ -8777,6 +8820,7 @@ export type Category =
|
|||
| "lint/suspicious/noArrayIndexKey"
|
||||
| "lint/suspicious/noAssignInExpressions"
|
||||
| "lint/suspicious/noAsyncPromiseExecutor"
|
||||
| "lint/suspicious/noBiomeFirstException"
|
||||
| "lint/suspicious/noBitwiseOperators"
|
||||
| "lint/suspicious/noCatchAssign"
|
||||
| "lint/suspicious/noClassAssign"
|
||||
|
|
@ -8853,6 +8897,7 @@ export type Category =
|
|||
| "lint/suspicious/noWith"
|
||||
| "lint/suspicious/useAdjacentOverloadSignatures"
|
||||
| "lint/suspicious/useAwait"
|
||||
| "lint/suspicious/useBiomeIgnoreFolder"
|
||||
| "lint/suspicious/useIterableCallbackReturn"
|
||||
| "lint/suspicious/useDefaultSwitchClauseLast"
|
||||
| "lint/suspicious/useErrorMessage"
|
||||
|
|
|
|||
72
packages/@biomejs/biome/configuration_schema.json
generated
72
packages/@biomejs/biome/configuration_schema.json
generated
|
|
@ -2590,6 +2590,16 @@
|
|||
]
|
||||
},
|
||||
"NoBarrelFileOptions": { "type": "object", "additionalProperties": false },
|
||||
"NoBiomeFirstExceptionConfiguration": {
|
||||
"anyOf": [
|
||||
{ "$ref": "#/definitions/RulePlainConfiguration" },
|
||||
{ "$ref": "#/definitions/RuleWithNoBiomeFirstExceptionOptions" }
|
||||
]
|
||||
},
|
||||
"NoBiomeFirstExceptionOptions": {
|
||||
"type": "object",
|
||||
"additionalProperties": false
|
||||
},
|
||||
"NoBitwiseOperatorsConfiguration": {
|
||||
"anyOf": [
|
||||
{ "$ref": "#/definitions/RulePlainConfiguration" },
|
||||
|
|
@ -5905,6 +5915,25 @@
|
|||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RuleWithNoBiomeFirstExceptionOptions": {
|
||||
"type": "object",
|
||||
"required": ["level"],
|
||||
"properties": {
|
||||
"fix": {
|
||||
"description": "The kind of the code actions emitted by the rule",
|
||||
"anyOf": [{ "$ref": "#/definitions/FixKind" }, { "type": "null" }]
|
||||
},
|
||||
"level": {
|
||||
"description": "The severity of the emitted diagnostics by the rule",
|
||||
"allOf": [{ "$ref": "#/definitions/RulePlainConfiguration" }]
|
||||
},
|
||||
"options": {
|
||||
"description": "Rule's options",
|
||||
"allOf": [{ "$ref": "#/definitions/NoBiomeFirstExceptionOptions" }]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RuleWithNoBitwiseOperatorsOptions": {
|
||||
"type": "object",
|
||||
"required": ["level"],
|
||||
|
|
@ -9784,6 +9813,25 @@
|
|||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RuleWithUseBiomeIgnoreFolderOptions": {
|
||||
"type": "object",
|
||||
"required": ["level"],
|
||||
"properties": {
|
||||
"fix": {
|
||||
"description": "The kind of the code actions emitted by the rule",
|
||||
"anyOf": [{ "$ref": "#/definitions/FixKind" }, { "type": "null" }]
|
||||
},
|
||||
"level": {
|
||||
"description": "The severity of the emitted diagnostics by the rule",
|
||||
"allOf": [{ "$ref": "#/definitions/RulePlainConfiguration" }]
|
||||
},
|
||||
"options": {
|
||||
"description": "Rule's options",
|
||||
"allOf": [{ "$ref": "#/definitions/UseBiomeIgnoreFolderOptions" }]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RuleWithUseBlockStatementsOptions": {
|
||||
"type": "object",
|
||||
"required": ["level"],
|
||||
|
|
@ -12440,6 +12488,13 @@
|
|||
{ "type": "null" }
|
||||
]
|
||||
},
|
||||
"noBiomeFirstException": {
|
||||
"description": "Prevents the use of the ! pattern in the first position of files.includes in the configuration file.",
|
||||
"anyOf": [
|
||||
{ "$ref": "#/definitions/NoBiomeFirstExceptionConfiguration" },
|
||||
{ "type": "null" }
|
||||
]
|
||||
},
|
||||
"noBitwiseOperators": {
|
||||
"description": "Disallow bitwise operators.",
|
||||
"anyOf": [
|
||||
|
|
@ -12988,6 +13043,13 @@
|
|||
{ "type": "null" }
|
||||
]
|
||||
},
|
||||
"useBiomeIgnoreFolder": {
|
||||
"description": "Promotes the correct usage for ignoring folders in the configuration file.",
|
||||
"anyOf": [
|
||||
{ "$ref": "#/definitions/UseBiomeIgnoreFolderConfiguration" },
|
||||
{ "type": "null" }
|
||||
]
|
||||
},
|
||||
"useDefaultSwitchClauseLast": {
|
||||
"description": "Enforce default clauses in switch statements to be last",
|
||||
"anyOf": [
|
||||
|
|
@ -13214,6 +13276,16 @@
|
|||
]
|
||||
},
|
||||
"UseAwaitOptions": { "type": "object", "additionalProperties": false },
|
||||
"UseBiomeIgnoreFolderConfiguration": {
|
||||
"anyOf": [
|
||||
{ "$ref": "#/definitions/RulePlainConfiguration" },
|
||||
{ "$ref": "#/definitions/RuleWithUseBiomeIgnoreFolderOptions" }
|
||||
]
|
||||
},
|
||||
"UseBiomeIgnoreFolderOptions": {
|
||||
"type": "object",
|
||||
"additionalProperties": false
|
||||
},
|
||||
"UseBlockStatementsConfiguration": {
|
||||
"anyOf": [
|
||||
{ "$ref": "#/definitions/RulePlainConfiguration" },
|
||||
|
|
|
|||
|
|
@ -99,7 +99,9 @@ export interface Workspace<Configuration, Diagnostic> {
|
|||
pullDiagnostics(
|
||||
params: PullDiagnosticsParams,
|
||||
): PullDiagnosticsResult<Diagnostic>;
|
||||
// biome-ignore lint: code generation is broken
|
||||
formatRange(params: FormatRangeParams): any;
|
||||
// biome-ignore lint: code generation is broken
|
||||
formatFile(params: FormatFileParams): any;
|
||||
getFormatterIr(params: GetFormatterIRParams): string;
|
||||
fixFile(params: FixFileParams): FixFileResult;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue