diff --git a/CHANGELOG.md b/CHANGELOG.md index fc35cfb3f13e..0adcbc5d07f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b - Add [noHeadImportInDocument](https://biomejs.dev/linter/rules/no-head-import-in-document/). Contributed by @kaioduarte - Add [noImgElement](https://biomejs.dev/linter/rules/no-img-element/). Contributed by @kaioduarte - Add [guardForIn](https://biomejs.dev/linter/rules/guard-for-in/). Contributed by @fireairforce +- Add [noUselessStringRaw](https://github.com/biomejs/biome/pull/4263). Contributed by @fireairforce #### Bug Fixes diff --git a/crates/biome_configuration/src/analyzer/linter/rules.rs b/crates/biome_configuration/src/analyzer/linter/rules.rs index e74d6c8a6843..f57c2e14820a 100644 --- a/crates/biome_configuration/src/analyzer/linter/rules.rs +++ b/crates/biome_configuration/src/analyzer/linter/rules.rs @@ -3377,6 +3377,10 @@ pub struct Nursery { #[serde(skip_serializing_if = "Option::is_none")] pub no_useless_escape_in_regex: Option>, + #[doc = "Disallow unnecessary String.raw function in template string literals without any escape sequence."] + #[serde(skip_serializing_if = "Option::is_none")] + pub no_useless_string_raw: + Option>, #[doc = "Disallow use of @value rule in css modules."] #[serde(skip_serializing_if = "Option::is_none")] pub no_value_at_rule: Option>, @@ -3479,6 +3483,7 @@ impl Nursery { "noUnknownPseudoElement", "noUnknownTypeSelector", "noUselessEscapeInRegex", + "noUselessStringRaw", "noValueAtRule", "useAdjacentOverloadSignatures", "useAriaPropsSupportedByRole", @@ -3522,10 +3527,10 @@ impl Nursery { RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42]), ]; const ALL_RULES_AS_FILTERS: &'static [RuleFilter<'static>] = &[ RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[0]), @@ -3572,6 +3577,7 @@ impl Nursery { RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44]), ]; #[doc = r" Retrieves the recommended rules"] pub(crate) fn is_recommended_true(&self) -> bool { @@ -3733,81 +3739,86 @@ impl Nursery { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28])); } } - if let Some(rule) = self.no_value_at_rule.as_ref() { + if let Some(rule) = self.no_useless_string_raw.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29])); } } - if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() { + if let Some(rule) = self.no_value_at_rule.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30])); } } - if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() { + if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31])); } } - if let Some(rule) = self.use_at_index.as_ref() { + if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32])); } } - if let Some(rule) = self.use_component_export_only_modules.as_ref() { + if let Some(rule) = self.use_at_index.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33])); } } - if let Some(rule) = self.use_consistent_curly_braces.as_ref() { + if let Some(rule) = self.use_component_export_only_modules.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34])); } } - if let Some(rule) = self.use_consistent_member_accessibility.as_ref() { + if let Some(rule) = self.use_consistent_curly_braces.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35])); } } - if let Some(rule) = self.use_deprecated_reason.as_ref() { + if let Some(rule) = self.use_consistent_member_accessibility.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36])); } } - if let Some(rule) = self.use_explicit_type.as_ref() { + if let Some(rule) = self.use_deprecated_reason.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37])); } } - if let Some(rule) = self.use_guard_for_in.as_ref() { + if let Some(rule) = self.use_explicit_type.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38])); } } - if let Some(rule) = self.use_import_restrictions.as_ref() { + if let Some(rule) = self.use_guard_for_in.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39])); } } - if let Some(rule) = self.use_sorted_classes.as_ref() { + if let Some(rule) = self.use_import_restrictions.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40])); } } - if let Some(rule) = self.use_strict_mode.as_ref() { + if let Some(rule) = self.use_sorted_classes.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41])); } } - if let Some(rule) = self.use_trim_start_end.as_ref() { + if let Some(rule) = self.use_strict_mode.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42])); } } - if let Some(rule) = self.use_valid_autocomplete.as_ref() { + if let Some(rule) = self.use_trim_start_end.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43])); } } + if let Some(rule) = self.use_valid_autocomplete.as_ref() { + if rule.is_enabled() { + index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44])); + } + } index_set } pub(crate) fn get_disabled_rules(&self) -> FxHashSet> { @@ -3957,81 +3968,86 @@ impl Nursery { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28])); } } - if let Some(rule) = self.no_value_at_rule.as_ref() { + if let Some(rule) = self.no_useless_string_raw.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29])); } } - if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() { + if let Some(rule) = self.no_value_at_rule.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30])); } } - if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() { + if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31])); } } - if let Some(rule) = self.use_at_index.as_ref() { + if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32])); } } - if let Some(rule) = self.use_component_export_only_modules.as_ref() { + if let Some(rule) = self.use_at_index.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33])); } } - if let Some(rule) = self.use_consistent_curly_braces.as_ref() { + if let Some(rule) = self.use_component_export_only_modules.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34])); } } - if let Some(rule) = self.use_consistent_member_accessibility.as_ref() { + if let Some(rule) = self.use_consistent_curly_braces.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35])); } } - if let Some(rule) = self.use_deprecated_reason.as_ref() { + if let Some(rule) = self.use_consistent_member_accessibility.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36])); } } - if let Some(rule) = self.use_explicit_type.as_ref() { + if let Some(rule) = self.use_deprecated_reason.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37])); } } - if let Some(rule) = self.use_guard_for_in.as_ref() { + if let Some(rule) = self.use_explicit_type.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38])); } } - if let Some(rule) = self.use_import_restrictions.as_ref() { + if let Some(rule) = self.use_guard_for_in.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39])); } } - if let Some(rule) = self.use_sorted_classes.as_ref() { + if let Some(rule) = self.use_import_restrictions.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40])); } } - if let Some(rule) = self.use_strict_mode.as_ref() { + if let Some(rule) = self.use_sorted_classes.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41])); } } - if let Some(rule) = self.use_trim_start_end.as_ref() { + if let Some(rule) = self.use_strict_mode.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42])); } } - if let Some(rule) = self.use_valid_autocomplete.as_ref() { + if let Some(rule) = self.use_trim_start_end.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43])); } } + if let Some(rule) = self.use_valid_autocomplete.as_ref() { + if rule.is_disabled() { + index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44])); + } + } index_set } #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"] @@ -4184,6 +4200,10 @@ impl Nursery { .no_useless_escape_in_regex .as_ref() .map(|conf| (conf.level(), conf.get_options())), + "noUselessStringRaw" => self + .no_useless_string_raw + .as_ref() + .map(|conf| (conf.level(), conf.get_options())), "noValueAtRule" => self .no_value_at_rule .as_ref() diff --git a/crates/biome_diagnostics_categories/src/categories.rs b/crates/biome_diagnostics_categories/src/categories.rs index f0b6584e3002..4d03ac67332e 100644 --- a/crates/biome_diagnostics_categories/src/categories.rs +++ b/crates/biome_diagnostics_categories/src/categories.rs @@ -182,6 +182,7 @@ define_categories! { "lint/nursery/noUnmatchableAnbSelector": "https://biomejs.dev/linter/rules/no-unmatchable-anb-selector", "lint/nursery/noUnusedFunctionParameters": "https://biomejs.dev/linter/rules/no-unused-function-parameters", "lint/nursery/noUselessEscapeInRegex": "https://biomejs.dev/linter/rules/no-useless-escape-in-regex", + "lint/nursery/noUselessStringRaw": "https://biomejs.dev/linter/rules/no-useless-string-raw", "lint/nursery/noValueAtRule": "https://biomejs.dev/linter/rules/no-value-at-rule", "lint/nursery/useAdjacentOverloadSignatures": "https://biomejs.dev/linter/rules/use-adjacent-overload-signatures", "lint/nursery/useAriaPropsSupportedByRole": "https://biomejs.dev/linter/rules/use-aria-props-supported-by-role", diff --git a/crates/biome_js_analyze/src/lint/nursery.rs b/crates/biome_js_analyze/src/lint/nursery.rs index 2f4de9545914..4a3341d01aca 100644 --- a/crates/biome_js_analyze/src/lint/nursery.rs +++ b/crates/biome_js_analyze/src/lint/nursery.rs @@ -23,6 +23,7 @@ pub mod no_static_element_interactions; pub mod no_substr; pub mod no_template_curly_in_string; pub mod no_useless_escape_in_regex; +pub mod no_useless_string_raw; pub mod use_adjacent_overload_signatures; pub mod use_aria_props_supported_by_role; pub mod use_at_index; @@ -62,6 +63,7 @@ declare_lint_group! { self :: no_substr :: NoSubstr , self :: no_template_curly_in_string :: NoTemplateCurlyInString , self :: no_useless_escape_in_regex :: NoUselessEscapeInRegex , + self :: no_useless_string_raw :: NoUselessStringRaw , self :: use_adjacent_overload_signatures :: UseAdjacentOverloadSignatures , self :: use_aria_props_supported_by_role :: UseAriaPropsSupportedByRole , self :: use_at_index :: UseAtIndex , diff --git a/crates/biome_js_analyze/src/lint/nursery/no_useless_string_raw.rs b/crates/biome_js_analyze/src/lint/nursery/no_useless_string_raw.rs new file mode 100644 index 000000000000..85f30f6578d9 --- /dev/null +++ b/crates/biome_js_analyze/src/lint/nursery/no_useless_string_raw.rs @@ -0,0 +1,103 @@ +use biome_analyze::{context::RuleContext, declare_lint_rule, Ast, Rule, RuleDiagnostic}; +use biome_console::markup; +use biome_js_syntax::{AnyJsTemplateElement, JsTemplateExpression}; +use biome_rowan::{AstNode, AstNodeList}; + +declare_lint_rule! { + /// Disallow unnecessary `String.raw` function in template string literals without any escape sequence. + /// + /// `String.raw` is useless when contains a raw string without any escape-like sequence. + /// + /// ## Examples + /// + /// ### Invalid + /// + /// ```js,expect_diagnostic + /// String.raw`a`; + /// ``` + /// + /// ```js,expect_diagnostic + /// String.raw`a ${v}`; + /// ``` + /// + /// ### Valid + /// + /// ```js + /// String.raw`\n ${a}`; + /// ``` + /// + /// ```js + /// String.raw`\n`; + /// ``` + pub NoUselessStringRaw { + version: "next", + name: "noUselessStringRaw", + language: "js", + recommended: false, + } +} + +impl Rule for NoUselessStringRaw { + type Query = Ast; + type State = (); + type Signals = Option; + type Options = (); + + fn run(ctx: &RuleContext) -> Self::Signals { + let node = ctx.query(); + let tag = node.tag()?; + let tag = tag.as_js_static_member_expression()?; + + let object = tag.object().ok()?; + let object_expr = object.as_js_identifier_expression()?; + let object_name = object_expr.name().ok()?.value_token().ok()?; + let object_name = object_name.text_trimmed(); + + let member = tag.member().ok()?; + let member_name = member.as_js_name()?.value_token().ok()?; + let member_name = member_name.text_trimmed(); + + if object_name != "String" || member_name != "raw" { + return None; + } + + if can_remove_string_raw(node) { + Some(()) + } else { + None + } + } + + fn diagnostic(ctx: &RuleContext, _state: &Self::State) -> Option { + let node = ctx.query(); + Some( + RuleDiagnostic::new( + rule_category!(), + node.range(), + markup! { + "String.raw is useless when the raw string doesn't contain any escape sequence." + }, + ) + .note(markup! { + "Remove the String.raw call beacause it's useless here, String.raw can deal with string which contains escape sequence like \\n, \\t, \\r, \\\\, \\\", \\\'." + }), + ) + } +} + +fn can_remove_string_raw(node: &JsTemplateExpression) -> bool { + !node.elements().iter().any(|element| { + match element { + AnyJsTemplateElement::JsTemplateElement(_) => false, + AnyJsTemplateElement::JsTemplateChunkElement(chunk) => { + match chunk.template_chunk_token() { + Ok(token) => token.text().contains('\\'), + Err(_) => { + // if found an error, return `true` means `String.raw` can't remove + true + } + } + } + } + }) +} diff --git a/crates/biome_js_analyze/src/options.rs b/crates/biome_js_analyze/src/options.rs index 5595abfb35c9..93ab2a833591 100644 --- a/crates/biome_js_analyze/src/options.rs +++ b/crates/biome_js_analyze/src/options.rs @@ -258,6 +258,8 @@ pub type NoUselessLoneBlockStatements = < lint :: complexity :: no_useless_lone_ pub type NoUselessRename = ::Options; pub type NoUselessStringConcat = < lint :: complexity :: no_useless_string_concat :: NoUselessStringConcat as biome_analyze :: Rule > :: Options ; +pub type NoUselessStringRaw = + ::Options; pub type NoUselessSwitchCase = ::Options; pub type NoUselessTernary = diff --git a/crates/biome_js_analyze/tests/specs/nursery/noUselessStringRaw/invalid.js b/crates/biome_js_analyze/tests/specs/nursery/noUselessStringRaw/invalid.js new file mode 100644 index 000000000000..1e994a2fb291 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noUselessStringRaw/invalid.js @@ -0,0 +1,3 @@ +String.raw`a`; +String.raw`abc`; +String.raw`a ${x}`; \ No newline at end of file diff --git a/crates/biome_js_analyze/tests/specs/nursery/noUselessStringRaw/invalid.js.snap b/crates/biome_js_analyze/tests/specs/nursery/noUselessStringRaw/invalid.js.snap new file mode 100644 index 000000000000..9df5e69159e2 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noUselessStringRaw/invalid.js.snap @@ -0,0 +1,56 @@ +--- +source: crates/biome_js_analyze/tests/spec_tests.rs +expression: invalid.js +--- +# Input +```jsx +String.raw`a`; +String.raw`abc`; +String.raw`a ${x}`; +``` + +# Diagnostics +``` +invalid.js:1:1 lint/nursery/noUselessStringRaw ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! String.raw is useless when the raw string doesn't contain any escape sequence. + + > 1 │ String.raw`a`; + │ ^^^^^^^^^^^^^ + 2 │ String.raw`abc`; + 3 │ String.raw`a ${x}`; + + i Remove the String.raw call beacause it's useless here, String.raw can deal with string which contains escape sequence like \n, \t, \r, \\, \", \'. + + +``` + +``` +invalid.js:2:1 lint/nursery/noUselessStringRaw ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! String.raw is useless when the raw string doesn't contain any escape sequence. + + 1 │ String.raw`a`; + > 2 │ String.raw`abc`; + │ ^^^^^^^^^^^^^^^ + 3 │ String.raw`a ${x}`; + + i Remove the String.raw call beacause it's useless here, String.raw can deal with string which contains escape sequence like \n, \t, \r, \\, \", \'. + + +``` + +``` +invalid.js:3:1 lint/nursery/noUselessStringRaw ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! String.raw is useless when the raw string doesn't contain any escape sequence. + + 1 │ String.raw`a`; + 2 │ String.raw`abc`; + > 3 │ String.raw`a ${x}`; + │ ^^^^^^^^^^^^^^^^^^ + + i Remove the String.raw call beacause it's useless here, String.raw can deal with string which contains escape sequence like \n, \t, \r, \\, \", \'. + + +``` diff --git a/crates/biome_js_analyze/tests/specs/nursery/noUselessStringRaw/valid.js b/crates/biome_js_analyze/tests/specs/nursery/noUselessStringRaw/valid.js new file mode 100644 index 000000000000..e37757edfa22 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noUselessStringRaw/valid.js @@ -0,0 +1,3 @@ +String.raw`\n a`; +String.raw`\n abc`; +String.raw`a ${x}`; \ No newline at end of file diff --git a/crates/biome_js_analyze/tests/specs/nursery/noUselessStringRaw/valid.js.snap b/crates/biome_js_analyze/tests/specs/nursery/noUselessStringRaw/valid.js.snap new file mode 100644 index 000000000000..df177133b718 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noUselessStringRaw/valid.js.snap @@ -0,0 +1,26 @@ +--- +source: crates/biome_js_analyze/tests/spec_tests.rs +expression: valid.js +--- +# Input +```jsx +String.raw`\n a`; +String.raw`\n abc`; +String.raw`a ${x}`; +``` + +# Diagnostics +``` +valid.js:3:1 lint/nursery/noUselessStringRaw ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! String.raw is useless when the raw string doesn't contain any escape sequence. + + 1 │ String.raw`\n a`; + 2 │ String.raw`\n abc`; + > 3 │ String.raw`a ${x}`; + │ ^^^^^^^^^^^^^^^^^^ + + i Remove the String.raw call beacause it's useless here, String.raw can deal with string which contains escape sequence like \n, \t, \r, \\, \", \'. + + +``` diff --git a/packages/@biomejs/backend-jsonrpc/src/workspace.ts b/packages/@biomejs/backend-jsonrpc/src/workspace.ts index aa177d187f0a..a38557656a37 100644 --- a/packages/@biomejs/backend-jsonrpc/src/workspace.ts +++ b/packages/@biomejs/backend-jsonrpc/src/workspace.ts @@ -1334,6 +1334,10 @@ export interface Nursery { * Disallow unnecessary escape sequence in regular expression literals. */ noUselessEscapeInRegex?: RuleFixConfiguration_for_Null; + /** + * Disallow unnecessary String.raw function in template string literals without any escape sequence. + */ + noUselessStringRaw?: RuleConfiguration_for_Null; /** * Disallow use of @value rule in css modules. */ @@ -2946,6 +2950,7 @@ export type Category = | "lint/nursery/noUnmatchableAnbSelector" | "lint/nursery/noUnusedFunctionParameters" | "lint/nursery/noUselessEscapeInRegex" + | "lint/nursery/noUselessStringRaw" | "lint/nursery/noValueAtRule" | "lint/nursery/useAdjacentOverloadSignatures" | "lint/nursery/useAriaPropsSupportedByRole" diff --git a/packages/@biomejs/biome/configuration_schema.json b/packages/@biomejs/biome/configuration_schema.json index 7df37a2bcf13..82f908c7d177 100644 --- a/packages/@biomejs/biome/configuration_schema.json +++ b/packages/@biomejs/biome/configuration_schema.json @@ -2288,6 +2288,13 @@ { "type": "null" } ] }, + "noUselessStringRaw": { + "description": "Disallow unnecessary String.raw function in template string literals without any escape sequence.", + "anyOf": [ + { "$ref": "#/definitions/RuleConfiguration" }, + { "type": "null" } + ] + }, "noValueAtRule": { "description": "Disallow use of @value rule in css modules.", "anyOf": [