From 6f9d67ea048fac01659b01334121be32e325e995 Mon Sep 17 00:00:00 2001
From: Victorien Elvinger <victorien@elvinger.fr>
Date: Tue, 7 May 2024 19:39:22 +0200
Subject: [PATCH] feat(useNamingConvention): add options for custom conventions

---
 Cargo.lock                                    |   31 +
 Cargo.toml                                    |    5 +-
 .../src/execute/migrate/eslint_typescript.rs  |    7 +-
 crates/biome_deserialize/Cargo.toml           |    1 +
 crates/biome_deserialize/src/impls.rs         |   29 +
 crates/biome_js_analyze/Cargo.toml            |    3 +
 .../src/lint/style/use_naming_convention.rs   | 1467 +++++++++++------
 crates/biome_js_analyze/src/utils.rs          |    1 +
 crates/biome_js_analyze/src/utils/regex.rs    |  175 ++
 .../invalidCatchParameter.js.snap             |   10 -
 .../useNamingConvention/invalidClass.js.snap  |   12 -
 .../invalidClassGetter.js.snap                |   42 +-
 .../invalidClassMethod.js.snap                |   48 +-
 .../invalidClassProperty.js.snap              |   62 +-
 .../invalidClassSetter.js.snap                |   42 +-
 .../invalidClassStaticGetter.js.snap          |   38 +-
 .../invalidClassStaticMethod.js.snap          |   60 +-
 .../invalidClassStaticSetter.js.snap          |   62 +-
 .../invalidCustomStyle.options.json           |   21 +
 .../useNamingConvention/invalidCustomStyle.ts |    8 +
 .../invalidCustomStyle.ts.snap                |   37 +
 .../invalidCustomStyleExceptions.options.json |   19 +
 .../invalidCustomStyleExceptions.ts           |    2 +
 .../invalidCustomStyleExceptions.ts.snap      |   28 +
 ...dCustomStyleUnderscorePrivate.options.json |   23 +
 .../invalidCustomStyleUnderscorePrivate.ts    |    3 +
 ...nvalidCustomStyleUnderscorePrivate.ts.snap |   24 +
 .../useNamingConvention/invalidEnum.ts.snap   |    8 -
 .../invalidEnumMember.ts.snap                 |   10 -
 .../invalidExportAlias.js.snap                |   16 +-
 .../invalidExportNamespace.js.snap            |    8 -
 .../invalidFunction.js.snap                   |   10 -
 .../invalidFunctionParameter.js.snap          |   10 +-
 .../invalidImportAlias.js.snap                |   30 +-
 .../invalidImportNamespace.js.snap            |    8 -
 .../invalidIndexParameter.ts.snap             |    8 -
 .../invalidInterface.ts.snap                  |   52 +-
 .../invalidLocalVariable.js.snap              |   20 +-
 .../invalidNamespace.ts.snap                  |   42 +-
 .../invalidNonAscii.js.snap                   |    4 +-
 .../invalidObjectGetter.js.snap               |    8 -
 .../invalidObjectMethod.js.snap               |   13 +-
 .../invalidObjectProperty.js.snap             |   12 -
 .../invalidObjectSetter.js.snap               |   12 -
 .../invalidParameterProperty.ts.snap          |   14 +-
 .../invalidSyllabary.js.snap                  |    4 +-
 .../invalidTopLevelVariable.ts.snap           |   32 +-
 .../invalidTypeAlias.ts.snap                  |   36 +-
 .../invalidTypeGetter.ts.snap                 |    8 -
 .../invalidTypeMethod.ts.snap                 |   13 +-
 .../invalidTypeParameter.ts.snap              |   16 -
 .../invalidTypeProperty.ts.snap               |   14 -
 .../invalidTypeReadonlyProperty.ts.snap       |   12 -
 .../invalidTypeSetter.ts.snap                 |   12 -
 .../malformedOptions.js.snap                  |   12 +-
 .../malformedOptions.options.json             |    2 +-
 .../validCustomStyle.options.json             |   19 +
 .../useNamingConvention/validCustomStyle.ts   |    1 +
 .../validCustomStyle.ts.snap                  |    8 +
 .../validCustomStyleExceptions.options.json   |   19 +
 .../validCustomStyleExceptions.ts             |    1 +
 .../validCustomStyleExceptions.ts.snap        |    8 +
 ...dCustomStyleUnderscorePrivate.options.json |   24 +
 .../validCustomStyleUnderscorePrivate.ts      |    3 +
 .../validCustomStyleUnderscorePrivate.ts.snap |   10 +
 .../src/utils/format_modifiers.rs             |    4 +-
 crates/biome_js_formatter/src/utils/mod.rs    |    6 +-
 crates/biome_js_syntax/Cargo.toml             |    2 +
 .../biome_js_syntax/src/class_member_ext.rs   |  100 ++
 crates/biome_js_syntax/src/lib.rs             |    1 +
 crates/biome_js_syntax/src/modifier_ext.rs    |  161 +-
 ...ing_convention_incorrect_options.json.snap |    4 +-
 crates/biome_string_case/src/lib.rs           |  347 +++-
 .../@biomejs/backend-jsonrpc/src/workspace.ts |   69 +-
 .../@biomejs/biome/configuration_schema.json  |  121 +-
 75 files changed, 2402 insertions(+), 1212 deletions(-)
 create mode 100644 crates/biome_js_analyze/src/utils/regex.rs
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyle.options.json
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyle.ts
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyle.ts.snap
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleExceptions.options.json
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleExceptions.ts
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleExceptions.ts.snap
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleUnderscorePrivate.options.json
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleUnderscorePrivate.ts
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleUnderscorePrivate.ts.snap
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyle.options.json
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyle.ts
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyle.ts.snap
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleExceptions.options.json
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleExceptions.ts
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleExceptions.ts.snap
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleUnderscorePrivate.options.json
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleUnderscorePrivate.ts
 create mode 100644 crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleUnderscorePrivate.ts.snap
 create mode 100644 crates/biome_js_syntax/src/class_member_ext.rs

diff --git a/Cargo.lock b/Cargo.lock
index 05da8870a25a..ca6befbfcd4e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -329,6 +329,7 @@ dependencies = [
  "indexmap 2.2.6",
  "schemars",
  "serde",
+ "smallvec",
 ]
 
 [[package]]
@@ -595,9 +596,12 @@ dependencies = [
  "biome_suppression",
  "biome_test_utils",
  "biome_unicode_table",
+ "bitflags 2.5.0",
+ "enumflags2",
  "insta",
  "lazy_static",
  "natord",
+ "regex",
  "roaring",
  "rustc-hash",
  "schemars",
@@ -690,6 +694,8 @@ dependencies = [
  "biome_js_factory",
  "biome_js_parser",
  "biome_rowan",
+ "bitflags 2.5.0",
+ "enumflags2",
  "schemars",
  "serde",
 ]
@@ -1552,6 +1558,26 @@ version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
 
+[[package]]
+name = "enumflags2"
+version = "0.7.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d"
+dependencies = [
+ "enumflags2_derive",
+]
+
+[[package]]
+name = "enumflags2_derive"
+version = "0.7.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+]
+
 [[package]]
 name = "env_logger"
 version = "0.8.4"
@@ -2880,9 +2906,11 @@ checksum = "7f55c82c700538496bdc329bb4918a81f87cc8888811bd123cf325a0f2f8d309"
 dependencies = [
  "dyn-clone",
  "indexmap 1.9.3",
+ "indexmap 2.2.6",
  "schemars_derive",
  "serde",
  "serde_json",
+ "smallvec",
 ]
 
 [[package]]
@@ -3071,6 +3099,9 @@ name = "smallvec"
 version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+dependencies = [
+ "serde",
+]
 
 [[package]]
 name = "socket2"
diff --git a/Cargo.toml b/Cargo.toml
index 7cbd01d9feea..596c9ffdbe56 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -157,6 +157,7 @@ bpaf               = { version = "0.9.9", features = ["derive"] }
 countme            = "3.0.1"
 crossbeam          = "0.8.4"
 dashmap            = "5.4.0"
+enumflags2         = "0.7.3"
 getrandom          = "0.2.14"
 ignore             = "0.4.21"
 indexmap           = { version = "2.2.6", features = ["serde"] }
@@ -170,12 +171,12 @@ quote              = "1.0.36"
 rayon              = "1.8.1"
 regex              = "1.10.4"
 rustc-hash         = "1.1.0"
-schemars           = "0.8.17"
+schemars           = { version = "0.8.17", features = ["indexmap2", "smallvec"] }
 serde              = { version = "1.0.200", features = ["derive"] }
 serde_json         = "1.0.116"
 similar            = "2.5.0"
 slotmap            = "1.0.7"
-smallvec           = { version = "1.10.0", features = ["union", "const_new"] }
+smallvec           = { version = "1.10.0", features = ["union", "const_new", "serde"] }
 syn                = "1.0.109"
 termcolor          = "1.4.1"
 tokio              = "1.36.0"
diff --git a/crates/biome_cli/src/execute/migrate/eslint_typescript.rs b/crates/biome_cli/src/execute/migrate/eslint_typescript.rs
index adc9457a2cfc..553e65d16d82 100644
--- a/crates/biome_cli/src/execute/migrate/eslint_typescript.rs
+++ b/crates/biome_cli/src/execute/migrate/eslint_typescript.rs
@@ -104,17 +104,18 @@ impl From<NamingConventionOptions> for use_naming_convention::NamingConventionOp
                 Some(NamingConventionCase::StrictCamel | NamingConventionCase::StrictPascal)
             ),
             require_ascii: false,
+            custom: Vec::new(),
             enum_member_case: enum_member_format
                 .and_then(|format| {
                     match format {
                         NamingConventionCase::Camel | NamingConventionCase::StrictCamel => {
-                            Some(use_naming_convention::EnumMemberCase::Camel)
+                            Some(use_naming_convention::Format::Camel)
                         }
                         NamingConventionCase::Pascal | NamingConventionCase::StrictPascal => {
-                            Some(use_naming_convention::EnumMemberCase::Pascal)
+                            Some(use_naming_convention::Format::Pascal)
                         }
                         NamingConventionCase::Upper => {
-                            Some(use_naming_convention::EnumMemberCase::Constant)
+                            Some(use_naming_convention::Format::Constant)
                         }
                         // Biome doesn't support `snake_case` for enum member
                         NamingConventionCase::Snake => None,
diff --git a/crates/biome_deserialize/Cargo.toml b/crates/biome_deserialize/Cargo.toml
index 30c9c5d67011..532180feb5f4 100644
--- a/crates/biome_deserialize/Cargo.toml
+++ b/crates/biome_deserialize/Cargo.toml
@@ -21,6 +21,7 @@ bitflags                 = { workspace = true }
 indexmap                 = { workspace = true, features = ["serde"] }
 schemars                 = { workspace = true, optional = true }
 serde                    = { workspace = true }
+smallvec                 = { workspace = true }
 
 [features]
 schema = ["schemars", "schemars/indexmap"]
diff --git a/crates/biome_deserialize/src/impls.rs b/crates/biome_deserialize/src/impls.rs
index 58fb0c3e53bf..dccef1ed546a 100644
--- a/crates/biome_deserialize/src/impls.rs
+++ b/crates/biome_deserialize/src/impls.rs
@@ -14,6 +14,7 @@ use std::{
     num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize},
     ops::Deref,
     path::PathBuf,
+    u8,
 };
 
 /// Type that allows deserializing a string without heap-allocation.
@@ -531,6 +532,34 @@ impl<T: Deserializable> Deserializable for Vec<T> {
     }
 }
 
+impl<T: Deserializable, const L: usize> Deserializable for smallvec::SmallVec<[T; L]> {
+    fn deserialize(
+        value: &impl DeserializableValue,
+        name: &str,
+        diagnostics: &mut Vec<DeserializationDiagnostic>,
+    ) -> Option<Self> {
+        struct Visitor<T, const L: usize>(PhantomData<T>);
+        impl<T: Deserializable, const L: usize> DeserializationVisitor for Visitor<T, L> {
+            type Output = smallvec::SmallVec<[T; L]>;
+            const EXPECTED_TYPE: VisitableType = VisitableType::ARRAY;
+            fn visit_array(
+                self,
+                values: impl Iterator<Item = Option<impl DeserializableValue>>,
+                _range: TextRange,
+                _name: &str,
+                diagnostics: &mut Vec<DeserializationDiagnostic>,
+            ) -> Option<Self::Output> {
+                Some(
+                    values
+                        .filter_map(|value| Deserializable::deserialize(&value?, "", diagnostics))
+                        .collect(),
+                )
+            }
+        }
+        value.deserialize(Visitor(PhantomData), name, diagnostics)
+    }
+}
+
 impl<T: Deserializable + Eq + Hash, S: BuildHasher + Default> Deserializable for HashSet<T, S> {
     fn deserialize(
         value: &impl DeserializableValue,
diff --git a/crates/biome_js_analyze/Cargo.toml b/crates/biome_js_analyze/Cargo.toml
index 7f8e5ba901b4..180e5f646132 100644
--- a/crates/biome_js_analyze/Cargo.toml
+++ b/crates/biome_js_analyze/Cargo.toml
@@ -26,8 +26,11 @@ biome_rowan              = { workspace = true }
 biome_string_case        = { workspace = true }
 biome_suppression        = { workspace = true }
 biome_unicode_table      = { workspace = true }
+bitflags                 = { workspace = true }
+enumflags2               = { workspace = true }
 lazy_static              = { workspace = true }
 natord                   = "1.0.9"
+regex                    = { workspace = true }
 roaring                  = "0.10.4"
 rustc-hash               = { workspace = true }
 schemars                 = { workspace = true, optional = true }
diff --git a/crates/biome_js_analyze/src/lint/style/use_naming_convention.rs b/crates/biome_js_analyze/src/lint/style/use_naming_convention.rs
index 7cbd5d487a5f..6e2242091dc2 100644
--- a/crates/biome_js_analyze/src/lint/style/use_naming_convention.rs
+++ b/crates/biome_js_analyze/src/lint/style/use_naming_convention.rs
@@ -1,9 +1,11 @@
-use std::str::FromStr;
+use std::ops::{Deref, Range};
 
 use crate::{
-    services::control_flow::AnyJsControlFlowRoot,
-    services::semantic::Semantic,
-    utils::rename::{AnyJsRenamableDeclaration, RenameSymbolExtensions},
+    services::{control_flow::AnyJsControlFlowRoot, semantic::Semantic},
+    utils::{
+        regex::RestrictedRegex,
+        rename::{AnyJsRenamableDeclaration, RenameSymbolExtensions},
+    },
     JsRuleAction,
 };
 use biome_analyze::{
@@ -11,21 +13,24 @@ use biome_analyze::{
     RuleSourceKind,
 };
 use biome_console::markup;
+use biome_deserialize::{DeserializableValidator, DeserializationDiagnostic};
 use biome_deserialize_macros::Deserializable;
 use biome_diagnostics::Applicability;
-use biome_js_semantic::CanBeImportedExported;
+use biome_js_semantic::{CanBeImportedExported, SemanticModel};
 use biome_js_syntax::{
     binding_ext::AnyJsBindingDeclaration, inner_string_text, AnyJsClassMember, AnyJsObjectMember,
     AnyJsVariableDeclaration, AnyTsTypeMember, JsIdentifierBinding, JsLiteralExportName,
-    JsLiteralMemberName, JsPrivateClassMemberName, JsSyntaxKind, JsSyntaxToken,
-    JsVariableDeclarator, JsVariableKind, TsEnumMember, TsIdentifierBinding, TsTypeParameterName,
+    JsLiteralMemberName, JsMethodModifierList, JsPrivateClassMemberName, JsPropertyModifierList,
+    JsSyntaxKind, JsSyntaxToken, JsVariableDeclarator, JsVariableKind, Modifier, TsEnumMember,
+    TsIdentifierBinding, TsMethodSignatureModifierList, TsPropertySignatureModifierList,
+    TsTypeParameterName,
 };
 use biome_rowan::{
-    declare_node_union, AstNode, AstNodeList, BatchMutationExt, SyntaxResult, TokenText,
+    declare_node_union, AstNode, BatchMutationExt, SyntaxResult, TextRange, TextSize, TokenText,
 };
-use biome_string_case::Case;
+use biome_string_case::{Case, Cases};
 use biome_unicode_table::is_js_ident;
-use serde::{Deserialize, Serialize};
+use enumflags2::BitFlags;
 use smallvec::SmallVec;
 
 #[cfg(feature = "schemars")]
@@ -37,6 +42,8 @@ declare_rule! {
     /// Enforcing [naming conventions](https://en.wikipedia.org/wiki/Naming_convention_(programming)) helps to keep the codebase consistent,
     /// and reduces overhead when thinking about the name [case] of a variable.
     ///
+    /// The following section describes the default conventions enforced by the rule.
+    ///
     /// ## Naming conventions
     ///
     /// All names can be prefixed and suffixed by underscores `_` and dollar signs `$`.
@@ -235,14 +242,25 @@ declare_rule! {
     ///
     /// ## Options
     ///
-    /// The rule provides two options that are detailed in the following subsections.
+    /// The rule provides several options that are detailed in the following subsections.
     ///
     /// ```json
     /// {
     ///     "//": "...",
     ///     "options": {
     ///         "strictCase": false,
-    ///         "enumMemberCase": "CONSTANT_CASE"
+    ///         "requireAscii": true,
+    ///         "enumMemberCase": "CONSTANT_CASE",
+    ///         "custon": [
+    ///             {
+    ///                 "selector": {
+    ///                     "kind": "memberLike",
+    ///                     "modifiers": ["private"]
+    ///                 },
+    ///                 "match": "_(.+)",
+    ///                 "formats": ["camelCase"]
+    ///             }
+    ///         ]
     ///     }
     /// }
     /// ```
@@ -278,6 +296,100 @@ declare_rule! {
     /// You can enforce another convention by setting `enumMemberCase` option.
     /// The supported cases are: [`PascalCase`], [`CONSTANT_CASE`], and [`camelCase`].
     ///
+    /// ### Custom conventions
+    ///
+    /// The `custom` option allows applying custom conventions.
+    /// The option takes an array of objects that includes a selector and some requirements.
+    ///
+    /// A selector descibes which names the convention applies to.
+    /// You can select a name based on three selectors:
+    ///
+    /// - `kind`: the kind of thed eclaration among:
+    ///   - `any` (default kind if the kind is unspecified)
+    ///   - `typeLike`
+    ///   - `class`
+    ///   - `interface`
+    ///   - `typeAlias`
+    ///   - [TODO]
+    /// - `modifiers`: an array of modifiers among:
+    ///   - `abstract`
+    ///   - `private`
+    ///   - `protected`
+    ///   - `readonly`
+    ///   - `static`
+    /// - `scope`: where the name appears. Allowd values:
+    ///   - `any`: anywhere (default value if the scope is unspecified)
+    ///   - `global`: the global scope (also includes the namespace scopes)
+    ///
+    /// The `custom` array of convention is traversed until the current name iss elected by a selector.
+    /// The reauirements of the convention are so verified on the name.
+    ///
+    /// A convention must specify at least one requirement among the following:
+    ///
+    /// - `match` provides a regular expression that the name must match.
+    ///   If the match captures a part of the name, then this part is checked against `formats`.
+    ///   Note that only the first capture is tested.
+    /// - `formats` indicates the format that the name must follow.
+    ///
+    /// If `match` is set and `formats` is unset,
+    /// then the part of the name captured by the regulat expression is forwarded to the next convention of the array.
+    ///
+    /// If a name reaches the end of the array, then we apply thed default conventions.
+    ///
+    /// In the following example:
+    /// = We require `static readonly` class members to be in ["CONSTANT_CASE"].
+    /// - We require `private` class members to start with an underscore `_` and to be in [`camelCase`].
+    /// - We require global constants to be in ["CONSTANT_CASE"] and
+    ///   we allow these constants to be enclosed by double underscores or to be named `_SPECIAL_`.
+    /// - All other names follow the default conventions
+    ///
+    ///```jsonc
+    /// {
+    ///     "//": "...",
+    ///     "options": {
+    ///         "custon": [
+    ///             {
+    ///                 "selector": {
+    ///                     "kind": "memberLike",
+    ///                     "modifiers": ["static", "readonly"]
+    ///                 },
+    ///                 "formats": ["CONSTANT_CASE"]
+    ///             },
+    ///             {
+    ///                 "selector": {
+    ///                     "kind": "memberLike",
+    ///                     "modifiers": ["private"]
+    ///                 },
+    ///                 "match": "_(.+)",
+    ///                 "formats": ["camelCase"]
+    ///             }, {
+    ///                 "selector": {
+    ///                     "kind": "const",
+    ///                     "scope": "global"
+    ///                 },
+    ///                 "match": "__(.+)__|_SPECIAL_|(.+)",
+    ///                 "formats": ["CONSTANT_CASE"]
+    ///             },
+    ///             // default conventions
+    ///         ]
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// ### Regular expression syntax
+    ///
+    /// The `match` option takes a regular expression taht supports the following syntaxes:
+    ///
+    /// - Greedy quantifiers `*`, `?`, `+`, `{n}`, `{n,m}`, `{n,}`, `{m}`
+    /// - Non-greedy quantifiers `*?`, `??`, `+?`, `{n}?`, `{n,m}?`, `{n,}?`, `{m}?`
+    /// - An ycharacter matcher `.`
+    /// - Character classes `[a-z]`, `[xyz]`, `[^a-z]`
+    /// - Alternations `|`
+    /// - Capturing groups `()`
+    /// - Non-capturing groups `(?:)`
+    /// - A limited set of escaped characters including all special characters
+    ///   and regular string escape characters `\f`, `\n`, `\r`, `\t`, `\v`
+    ///
     /// [case]: https://en.wikipedia.org/wiki/Naming_convention_(programming)#Examples_of_multiple-word_identifier_formats
     /// [`camelCase`]: https://en.wikipedia.org/wiki/Camel_case
     /// [`PascalCase`]: https://en.wikipedia.org/wiki/Camel_case
@@ -301,157 +413,179 @@ impl Rule for UseNamingConvention {
     fn run(ctx: &RuleContext<Self>) -> Self::Signals {
         let node = ctx.query();
         let options = ctx.options();
-        let element = Named::from_name(node)?;
-        let allowed_cases = element.allowed_cases(options);
-        if allowed_cases.is_empty() {
-            // No naming convention to verify.
-            return None;
-        }
         let name = node.name().ok()?;
-        let name = name.text();
+        let mut name = name.text();
         if !is_js_ident(name) {
-            // ignore non-identifier strings
+            // Ignore non-identifier strings
             return None;
         }
-        let trimmed_name = trim_underscore_dollar(name);
-        if options.require_ascii && !trimmed_name.is_ascii() {
+        if options.require_ascii && !name.is_ascii() {
             return Some(State {
-                element,
+                convention_selector: Selector::default(),
+                name_range: Range {
+                    start: 0u16,
+                    end: name.len() as u16,
+                },
                 suggestion: Suggestion::Ascii,
             });
         }
-        let actual_case = Case::identify(trimmed_name, options.strict_case);
-        if actual_case == Case::Uni
-            || trimmed_name.is_empty()
-            || allowed_cases
-                .iter()
-                .any(|&expected_style| actual_case.is_compatible_with(expected_style))
+        let mut name_range_start = 0;
+        let node_selector = Selector::from_name(node)?;
+        let default_convention = node_selector.default_convention(options);
+        for convention in options
+            .custom
+            .iter()
+            .filter(|convention| node_selector.contains(convention.selector))
+            .chain([&default_convention])
         {
-            // Valid case
-            return None;
-        }
-        let preferred_case = element.allowed_cases(ctx.options())[0];
-        let new_trimmed_name = preferred_case.convert(trimmed_name);
-        if trimmed_name != new_trimmed_name {
-            Some(State {
-                element,
-                suggestion: Suggestion::Name(name.replacen(trimmed_name, &new_trimmed_name, 1)),
-            })
-        } else {
-            Some(State {
-                element,
-                suggestion: Suggestion::None,
-            })
+            if let Some(matching) = &convention.matching {
+                let Some(capture) = matching.captures(name) else {
+                    return Some(State {
+                        convention_selector: convention.selector,
+                        name_range: Range {
+                            start: name_range_start as u16,
+                            end: (name_range_start + name.len()) as u16,
+                        },
+                        suggestion: Suggestion::Match(matching.as_source().to_string()),
+                    });
+                };
+                if let Some(first_match) = capture.iter().skip(1).find_map(|x| x) {
+                    name_range_start += first_match.start();
+                    name = first_match.as_str();
+                } else {
+                    // Match without any capture implies a valid case
+                    return None;
+                }
+            }
+            if !convention.formats.is_empty() {
+                let actual_case = Case::identify(name, options.strict_case);
+                if actual_case == Case::Uni
+                    || name.is_empty()
+                    || convention.formats.contains(actual_case)
+                {
+                    // Valid case
+                    return None;
+                }
+                return Some(State {
+                    convention_selector: convention.selector,
+                    name_range: Range {
+                        start: name_range_start as u16,
+                        end: (name_range_start + name.len()) as u16,
+                    },
+                    suggestion: Suggestion::Formats(convention.formats.clone()),
+                });
+            }
         }
+        None
     }
 
     fn diagnostic(ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> {
         let State {
-            element,
+            convention_selector,
+            name_range,
             suggestion,
         } = state;
         let options = ctx.options();
-        let name = ctx.query().name().ok()?;
-        let name = name.text();
-        let trimmed_name = trim_underscore_dollar(name);
-        let allowed_cases = element.allowed_cases(ctx.options());
-        let allowed_case_names = allowed_cases
-            .iter()
-            .map(|style| style.to_string())
-            .collect::<SmallVec<[_; 3]>>()
-            .join(" or ");
-        let trimmed_info = if name != trimmed_name {
-            markup! {" trimmed as `"{trimmed_name}"`"}.to_owned()
+        let node = ctx.query();
+        let name_token = node.name_token().ok()?;
+        let name_token_range = name_token.text_trimmed_range();
+        let name_token_range = if matches!(
+            name_token.kind(),
+            JsSyntaxKind::JS_STRING_LITERAL | JsSyntaxKind::JSX_STRING_LITERAL
+        ) {
+            name_token_range + TextSize::from(1) - TextSize::from(1)
         } else {
-            markup! {""}.to_owned()
+            name_token_range
         };
-        if matches!(suggestion, Suggestion::Ascii) {
-            return Some(RuleDiagnostic::new(
-                rule_category!(),
-                ctx.query().syntax().text_trimmed_range(),
-                markup! {
-                    "This "<Emphasis>{element.to_string()}</Emphasis>" name"{trimmed_info}" should be in ASCII because "<Emphasis>"requireAscii"</Emphasis>"` is set to `true`."
-                },
-            ).note(markup! {
-                "If you want to use non-ASCII names, then set the "<Emphasis>"requireAscii"</Emphasis>" option to `false`.\nSee the rule "<Hyperlink href="https://biomejs.dev/linter/rules/use-naming-convention#options">"options"</Hyperlink>" for more details."
-            }));
-        }
-        if options.strict_case {
-            let case_type = Case::identify(name, false);
-            let case_strict = Case::identify(name, true);
-            if case_type == Case::Camel && case_strict == Case::Unknown {
-                return Some(RuleDiagnostic::new(
+        let name = inner_string_text(&name_token);
+        let name = name.text();
+        match suggestion {
+            Suggestion::Ascii => {
+                Some(RuleDiagnostic::new(
                     rule_category!(),
-                    ctx.query().syntax().text_trimmed_range(),
+                    name_token_range,
                     markup! {
-                        "Two consecutive uppercase characters are not allowed in camelCase and PascalCase because "<Emphasis>"strictCase"</Emphasis>" is set to `true`."
+                        "This "<Emphasis>{format_args!("{convention_selector}")}</Emphasis>" name should be in ASCII because "<Emphasis>"requireAscii"</Emphasis>" is set to `true`."
                     },
                 ).note(markup! {
-                    "If you want to use consecutive uppercase characters in camelCase and PascalCase, then set the "<Emphasis>"strictCase"</Emphasis>" option to `false`.\nSee the rule "<Hyperlink href="https://biomejs.dev/linter/rules/use-naming-convention#options">"options"</Hyperlink>" for more details."
-                }));
+                    "If you want to use non-ASCII names, then set the "<Emphasis>"requireAscii"</Emphasis>" option to `false`.\nSee the rule "<Hyperlink href="https://biomejs.dev/linter/rules/use-naming-convention#options">"options"</Hyperlink>" for more details."
+                }))
             }
-        }
-        let diagnostic = RuleDiagnostic::new(
-            rule_category!(),
-            ctx.query().syntax().text_trimmed_range(),
-            markup! {
-                "This "<Emphasis>{element.to_string()}</Emphasis>" name"{trimmed_info}" should be in "<Emphasis>{allowed_case_names}</Emphasis>"."
+            Suggestion::Match(regex) => {
+                let name_token_range = name_token_range.add_start(TextSize::from(name_range.start as u32)).sub_end(name_token_range.len() - TextSize::from(name_range.len() as u32));
+                Some(RuleDiagnostic::new(
+                    rule_category!(),
+                    name_token_range,
+                    markup! {
+                        "This "<Emphasis>{format_args!("{convention_selector}")}</Emphasis>" name part should match the following regex "<Emphasis>"/"{regex}"/"</Emphasis>"."
+                    },
+                ))
+            }
+            Suggestion::Formats(expected_cases) => {
+                let name_token_range = TextRange::at(name_token_range.start() + TextSize::from(name_range.start as u32), TextSize::from(name_range.len() as u32));
+                if options.strict_case && (expected_cases.contains(Case::Camel) || expected_cases.contains(Case::Pascal)) {
+                    let trimmed_name = &name[(name_range.start as _)..(name_range.end as _)];
+                    let actual_case = Case::identify(trimmed_name, false);
+                    if matches!(actual_case, Case::Camel | Case::Pascal)
+                        && Case::identify(trimmed_name, true) == Case::Unknown
+                    {
+                        return Some(RuleDiagnostic::new(
+                            rule_category!(),
+                            name_token_range,
+                            markup! {
+                                "Two consecutive uppercase characters are not allowed in "{format_args!("{actual_case}")}" because "<Emphasis>"strictCase"</Emphasis>" is set to `true`."
+                            },
+                        ).note(markup! {
+                            "If you want to use consecutive uppercase characters in "{format_args!("{actual_case}")}", then set the "<Emphasis>"strictCase"</Emphasis>" option to `false`.\nSee the rule "<Hyperlink href="https://biomejs.dev/linter/rules/use-naming-convention#options">"options"</Hyperlink>" for more details."
+                        }));
+                    }
+                }
+                let trimmed_info = if name_range.start > 0 || name_range.len() < name.len() {
+                    " part"
+                } else {
+                    ""
+                };
+                let expected_case_names = expected_cases
+                    .into_iter()
+                    .map(|case| case.to_string())
+                    .collect::<SmallVec<[_; 4]>>()
+                    .join(" or ");
+                Some(RuleDiagnostic::new(
+                    rule_category!(),
+                    name_token_range,
+                    markup! {
+                        "This "<Emphasis>{format_args!("{convention_selector}")}</Emphasis>" name"{trimmed_info}" should be in "<Emphasis>{expected_case_names}</Emphasis>"."
+                    },
+                ))
             },
-        );
-        Some(if let Suggestion::Name(suggested_name) = suggestion {
-            diagnostic.note(markup! {
-                "The name could be renamed to `"{suggested_name}"`."
-            })
-        } else {
-            diagnostic
-        })
+        }
     }
 
     fn action(ctx: &RuleContext<Self>, state: &Self::State) -> Option<JsRuleAction> {
         let State {
-            element,
-            suggestion,
-        } = state;
-        let Suggestion::Name(suggested_name) = suggestion else {
+            name_range,
+            suggestion: Suggestion::Formats(expected_cases),
+            ..
+        } = state
+        else {
             return None;
         };
         let node = ctx.query();
+        let name = node.name().ok()?;
+        let name = name.text();
+        let preferred_case = expected_cases.into_iter().next()?;
+        let new_name_part =
+            preferred_case.convert(&name[(name_range.start as _)..(name_range.end as _)]);
+        let mut new_name =
+            String::with_capacity(name.len() + new_name_part.len() - name_range.len());
+        new_name.push_str(&name[..(name_range.start as _)]);
+        new_name.push_str(&new_name_part);
+        new_name.push_str(&name[(name_range.end as _)..]);
+        let node = ctx.query();
         let model = ctx.model();
         let mut mutation = ctx.root().begin();
-        let renamable = match node {
-            AnyIdentifierBindingLike::JsIdentifierBinding(binding) => {
-                if binding.is_exported(model) {
-                    return None;
-                }
-                // Property parameters are also class properties.
-                // Shorthand binding patterns such as `const { a_a } = x;` should not be renamed.
-                // Shorthand named import specifiers such as `import { a_a } from "mod";` should not be renamed.
-                if let Some(
-                    AnyJsBindingDeclaration::TsPropertyParameter(_)
-                    | AnyJsBindingDeclaration::JsObjectBindingPatternShorthandProperty(_)
-                    | AnyJsBindingDeclaration::JsShorthandNamedImportSpecifier(_),
-                ) = binding.declaration()
-                {
-                    return None;
-                }
-
-                Some(AnyJsRenamableDeclaration::JsIdentifierBinding(
-                    binding.clone(),
-                ))
-            }
-            AnyIdentifierBindingLike::TsIdentifierBinding(binding) => {
-                if binding.is_exported(model) {
-                    return None;
-                }
-                Some(AnyJsRenamableDeclaration::TsIdentifierBinding(
-                    binding.clone(),
-                ))
-            }
-            _ => None,
-        };
-        if let Some(renamable) = renamable {
-            let preferred_case = element.allowed_cases(ctx.options())[0];
-            let renamed = mutation.rename_any_renamable_node(model, renamable, &suggested_name[..]);
+        if let Some(renamable) = renamable(node, model) {
+            let renamed = mutation.rename_any_renamable_node(model, renamable, &new_name[..]);
             if renamed {
                 return Some(JsRuleAction {
                     category: ActionCategory::QuickFix,
@@ -499,22 +633,62 @@ impl AnyIdentifierBindingLike {
 
 #[derive(Debug)]
 pub struct State {
-    element: Named,
+    // Selector of the convention which is not fullfilled.
+    convention_selector: Selector,
+    // Range of the name where the suggestion applies
+    name_range: Range<u16>,
     suggestion: Suggestion,
 }
 
 #[derive(Debug)]
 pub enum Suggestion {
-    /// No suggestion
-    None,
-    /// Suggest aa new name
-    Name(String),
-    /// Use only ASCII
+    /// Use only ASCII characters
     Ascii,
+    /// Use a name that matches this regex
+    Match(String),
+    /// Use a name that follows one of these formats
+    Formats(Formats),
+}
+
+fn renamable(
+    node: &AnyIdentifierBindingLike,
+    model: &SemanticModel,
+) -> Option<AnyJsRenamableDeclaration> {
+    match node {
+        AnyIdentifierBindingLike::JsIdentifierBinding(binding) => {
+            if binding.is_exported(model) {
+                return None;
+            }
+            // Property parameters are also class properties.
+            // Shorthand binding patterns such as `const { a_a } = x;` should not be renamed.
+            // Shorthand named import specifiers such as `import { a_a } from "mod";` should not be renamed.
+            if let Some(
+                AnyJsBindingDeclaration::TsPropertyParameter(_)
+                | AnyJsBindingDeclaration::JsObjectBindingPatternShorthandProperty(_)
+                | AnyJsBindingDeclaration::JsShorthandNamedImportSpecifier(_),
+            ) = binding.declaration()
+            {
+                return None;
+            }
+
+            Some(AnyJsRenamableDeclaration::JsIdentifierBinding(
+                binding.clone(),
+            ))
+        }
+        AnyIdentifierBindingLike::TsIdentifierBinding(binding) => {
+            if binding.is_exported(model) {
+                return None;
+            }
+            Some(AnyJsRenamableDeclaration::TsIdentifierBinding(
+                binding.clone(),
+            ))
+        }
+        _ => None,
+    }
 }
 
 /// Rule's options.
-#[derive(Debug, Clone, Deserialize, Deserializable, Eq, PartialEq, Serialize)]
+#[derive(Debug, Clone, Deserializable, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
 #[cfg_attr(feature = "schemars", derive(JsonSchema))]
 #[serde(rename_all = "camelCase", deny_unknown_fields)]
 pub struct NamingConventionOptions {
@@ -527,282 +701,208 @@ pub struct NamingConventionOptions {
     #[serde(default, skip_serializing_if = "is_default")]
     pub require_ascii: bool,
 
+    #[serde(default, skip_serializing_if = "Vec::is_empty")]
+    pub custom: Vec<Convention>,
+
     /// Allowed cases for _TypeScript_ `enum` member names.
     #[serde(default, skip_serializing_if = "is_default")]
-    pub enum_member_case: EnumMemberCase,
+    pub enum_member_case: Format,
+}
+impl Default for NamingConventionOptions {
+    fn default() -> Self {
+        Self {
+            strict_case: true,
+            require_ascii: false,
+            custom: Vec::new(),
+            enum_member_case: Format::default(),
+        }
+    }
 }
 
 const fn enabled() -> bool {
     true
 }
-
 const fn is_enabled(value: &bool) -> bool {
     *value
 }
-
 fn is_default<T: Default + Eq>(value: &T) -> bool {
     value == &T::default()
 }
 
-impl Default for NamingConventionOptions {
-    fn default() -> Self {
-        Self {
-            strict_case: true,
-            require_ascii: false,
-            enum_member_case: EnumMemberCase::default(),
+#[derive(
+    Clone, Debug, Default, Deserializable, Eq, PartialEq, serde::Deserialize, serde::Serialize,
+)]
+#[cfg_attr(feature = "schemars", derive(JsonSchema))]
+#[serde(default, deny_unknown_fields)]
+#[deserializable(with_validator)]
+pub struct Convention {
+    #[serde(skip_serializing_if = "is_default")]
+    selector: Selector,
+    #[serde(rename = "match", skip_serializing_if = "Option::is_none")]
+    matching: Option<RestrictedRegex>,
+    #[serde(skip_serializing_if = "is_default")]
+    formats: Formats,
+}
+
+impl DeserializableValidator for Convention {
+    fn validate(
+        &mut self,
+        _name: &str,
+        range: biome_rowan::TextRange,
+        diagnostics: &mut Vec<biome_deserialize::DeserializationDiagnostic>,
+    ) -> bool {
+        if self.formats.is_empty() && self.matching.is_none() {
+            diagnostics.push(
+                DeserializationDiagnostic::new(
+                    "At least one field among `format` and `match` must be set.",
+                )
+                .with_range(range),
+            );
+            false
+        } else {
+            true
         }
     }
 }
 
-/// Supported cases for TypeScript `enum` member names.
-#[derive(Clone, Copy, Debug, Default, Deserialize, Deserializable, Eq, PartialEq, Serialize)]
+#[derive(
+    Clone, Copy, Debug, Default, Deserializable, Eq, PartialEq, serde::Deserialize, serde::Serialize,
+)]
 #[cfg_attr(feature = "schemars", derive(JsonSchema))]
-pub enum EnumMemberCase {
-    /// PascalCase
-    #[serde(rename = "PascalCase")]
-    #[default]
-    Pascal,
-
-    /// CONSTANT_CASE
-    #[serde(rename = "CONSTANT_CASE")]
-    Constant,
-
-    /// camelCase
-    #[serde(rename = "camelCase")]
-    Camel,
+#[serde(default, deny_unknown_fields)]
+struct Selector {
+    #[serde(skip_serializing_if = "is_default")]
+    kind: Kind,
+    #[serde(skip_serializing_if = "is_default")]
+    modifiers: Modifiers,
+    #[serde(skip_serializing_if = "is_default")]
+    scope: Scope,
 }
 
-impl FromStr for EnumMemberCase {
-    type Err = &'static str;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "PascalCase" => Ok(Self::Pascal),
-            "CONSTANT_CASE" => Ok(Self::Constant),
-            "camelCase" => Ok(Self::Camel),
-            _ => Err("Value not supported for enum member case"),
+impl From<Kind> for Selector {
+    fn from(kind: Kind) -> Self {
+        Self {
+            kind,
+            modifiers: Modifiers::default(),
+            scope: Scope::Any,
         }
     }
 }
-
-impl From<EnumMemberCase> for Case {
-    fn from(case: EnumMemberCase) -> Case {
-        match case {
-            EnumMemberCase::Pascal => Case::Pascal,
-            EnumMemberCase::Constant => Case::Constant,
-            EnumMemberCase::Camel => Case::Camel,
-        }
+impl std::fmt::Display for Selector {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}{}{}", self.scope, self.modifiers, self.kind)
     }
 }
+impl Selector {
+    fn with_modifiers(kind: Kind, modifiers: impl Into<Modifiers>) -> Self {
+        Self {
+            kind,
+            modifiers: modifiers.into(),
+            ..Default::default()
+        }
+    }
 
-/// Named elements with an attached naming convention.
-///
-/// [Named::from_name] enables to get the element from an [AnyName].
-/// [Named::allowed_cases] enables to get a list of allowed cases for a given element.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-enum Named {
-    CatchParameter,
-    Class,
-    ClassGetter,
-    ClassMethod,
-    ClassProperty,
-    ClassSetter,
-    ClassStaticGetter,
-    ClassStaticMethod,
-    ClassStaticProperty,
-    ClassStaticSetter,
-    DestructuredObjectMember,
-    Enum,
-    EnumMember,
-    Export,
-    ExportAlias,
-    ExportNamespace,
-    Function,
-    FunctionParameter,
-    Import,
-    ImportAlias,
-    ImportNamespace,
-    IndexParameter,
-    Interface,
-    LocalConst,
-    LocalLet,
-    LocalVar,
-    LocalUsing,
-    LocalVariable,
-    Namespace,
-    ObjectGetter,
-    ObjectMethod,
-    ObjectProperty,
-    ObjectSetter,
-    ParameterProperty,
-    TopLevelConst,
-    TopLevelLet,
-    TopLevelVar,
-    TypeAlias,
-    TypeGetter,
-    TypeMethod,
-    TypeProperty,
-    TypeReadonlyProperty,
-    TypeSetter,
-    TypeParameter,
-}
+    fn with_cope(kind: Kind, scope: Scope) -> Self {
+        Self {
+            kind,
+            scope,
+            ..Default::default()
+        }
+    }
 
-impl Named {
-    fn from_name(js_name: &AnyIdentifierBindingLike) -> Option<Named> {
+    fn from_name(js_name: &AnyIdentifierBindingLike) -> Option<Selector> {
         match js_name {
             AnyIdentifierBindingLike::JsIdentifierBinding(binding) => {
-                Named::from_binding_declaration(&binding.declaration()?)
+                Selector::from_binding_declaration(&binding.declaration()?)
             }
             AnyIdentifierBindingLike::TsIdentifierBinding(binding) => {
-                Named::from_binding_declaration(&binding.declaration()?)
+                Selector::from_binding_declaration(&binding.declaration()?)
             }
             AnyIdentifierBindingLike::JsLiteralMemberName(member_name) => {
                 if let Some(member) = member_name.parent::<AnyJsClassMember>() {
-                    Named::from_class_member(&member)
+                    Selector::from_class_member(&member)
                 } else if let Some(member) = member_name.parent::<AnyTsTypeMember>() {
-                    Named::from_type_member(&member)
+                    Selector::from_type_member(&member)
                 } else if let Some(member) = member_name.parent::<AnyJsObjectMember>() {
-                    Named::from_object_member(&member)
+                    Selector::from_object_member(&member)
                 } else if member_name.parent::<TsEnumMember>().is_some() {
-                    Some(Named::EnumMember)
+                    Some(Kind::EnumMember.into())
                 } else {
                     None
                 }
             }
             AnyIdentifierBindingLike::JsPrivateClassMemberName(member_name) => {
-                Named::from_class_member(&member_name.parent::<AnyJsClassMember>()?)
+                Selector::from_class_member(&member_name.parent::<AnyJsClassMember>()?)
             }
             AnyIdentifierBindingLike::JsLiteralExportName(export_name) => {
                 let parent = export_name.syntax().parent()?;
                 match parent.kind() {
-                    JsSyntaxKind::JS_NAMED_IMPORT_SPECIFIER => Some(Named::Import),
-                    JsSyntaxKind::JS_EXPORT_NAMED_FROM_SPECIFIER => Some(Named::Export),
-                    JsSyntaxKind::JS_EXPORT_NAMED_SPECIFIER => Some(Named::ExportAlias),
+                    JsSyntaxKind::JS_NAMED_IMPORT_SPECIFIER
+                    | JsSyntaxKind::JS_EXPORT_NAMED_FROM_SPECIFIER => None,
+                    JsSyntaxKind::JS_EXPORT_NAMED_SPECIFIER => Some(Kind::ExportAlias.into()),
                     JsSyntaxKind::JS_EXPORT_AS_CLAUSE => {
                         if parent.parent()?.kind() == JsSyntaxKind::JS_EXPORT_FROM_CLAUSE {
-                            Some(Named::ExportNamespace)
+                            Some(Kind::ExportNamespace.into())
                         } else {
-                            Some(Named::ExportAlias)
+                            Some(Kind::ExportAlias.into())
                         }
                     }
                     _ => None,
                 }
             }
-            AnyIdentifierBindingLike::TsTypeParameterName(_) => Some(Named::TypeParameter),
+            AnyIdentifierBindingLike::TsTypeParameterName(_) => Some(Kind::TypeParameter.into()),
         }
     }
 
-    fn from_class_member(member: &AnyJsClassMember) -> Option<Named> {
-        match member {
+    fn from_class_member(member: &AnyJsClassMember) -> Option<Selector> {
+        let Selector {
+            kind,
+            modifiers,
+            scope,
+        } = match member {
             AnyJsClassMember::JsBogusMember(_)
             | AnyJsClassMember::JsConstructorClassMember(_)
             | AnyJsClassMember::TsConstructorSignatureClassMember(_)
             | AnyJsClassMember::JsEmptyClassMember(_)
-            | AnyJsClassMember::JsStaticInitializationBlockClassMember(_) => None,
-            AnyJsClassMember::TsIndexSignatureClassMember(_) => Some(Named::IndexParameter),
+            | AnyJsClassMember::JsStaticInitializationBlockClassMember(_) => return None,
+            AnyJsClassMember::TsIndexSignatureClassMember(_) => Kind::IndexParameter.into(),
             AnyJsClassMember::JsGetterClassMember(getter) => {
-                let is_static = getter
-                    .modifiers()
-                    .iter()
-                    .any(|modifier| modifier.as_js_static_modifier().is_some());
-                Some(if is_static {
-                    Named::ClassStaticGetter
-                } else {
-                    Named::ClassGetter
-                })
+                Selector::with_modifiers(Kind::ClassGetter, getter.modifiers())
             }
             AnyJsClassMember::TsGetterSignatureClassMember(getter) => {
-                let is_static = getter
-                    .modifiers()
-                    .iter()
-                    .any(|modifier| modifier.as_js_static_modifier().is_some());
-                Some(if is_static {
-                    Named::ClassStaticGetter
-                } else {
-                    Named::ClassGetter
-                })
+                Selector::with_modifiers(Kind::ClassGetter, getter.modifiers())
             }
             AnyJsClassMember::JsMethodClassMember(method) => {
-                let is_static = method
-                    .modifiers()
-                    .iter()
-                    .any(|modifier| modifier.as_js_static_modifier().is_some());
-                Some(if is_static {
-                    Named::ClassStaticMethod
-                } else {
-                    Named::ClassMethod
-                })
+                Selector::with_modifiers(Kind::ClassMethod, method.modifiers())
             }
             AnyJsClassMember::TsMethodSignatureClassMember(method) => {
-                let is_static = method
-                    .modifiers()
-                    .iter()
-                    .any(|modifier| modifier.as_js_static_modifier().is_some());
-                Some(if is_static {
-                    Named::ClassStaticMethod
-                } else {
-                    Named::ClassMethod
-                })
+                Selector::with_modifiers(Kind::ClassMethod, method.modifiers())
             }
             AnyJsClassMember::JsPropertyClassMember(property) => {
-                let is_static = property
-                    .modifiers()
-                    .iter()
-                    .any(|modifier| modifier.as_js_static_modifier().is_some());
-                Some(if is_static {
-                    Named::ClassStaticProperty
-                } else {
-                    Named::ClassProperty
-                })
+                Selector::with_modifiers(Kind::ClassProperty, property.modifiers())
             }
             AnyJsClassMember::TsPropertySignatureClassMember(property) => {
-                let is_static = property
-                    .modifiers()
-                    .iter()
-                    .any(|modifier| modifier.as_js_static_modifier().is_some());
-                Some(if is_static {
-                    Named::ClassStaticProperty
-                } else {
-                    Named::ClassProperty
-                })
+                Selector::with_modifiers(Kind::ClassProperty, property.modifiers())
             }
             AnyJsClassMember::TsInitializedPropertySignatureClassMember(property) => {
-                let is_static = property
-                    .modifiers()
-                    .iter()
-                    .any(|modifier| modifier.as_js_static_modifier().is_some());
-                Some(if is_static {
-                    Named::ClassStaticProperty
-                } else {
-                    Named::ClassProperty
-                })
+                Selector::with_modifiers(Kind::ClassProperty, property.modifiers())
             }
             AnyJsClassMember::JsSetterClassMember(setter) => {
-                let is_static = setter
-                    .modifiers()
-                    .iter()
-                    .any(|modifier| modifier.as_js_static_modifier().is_some());
-                Some(if is_static {
-                    Named::ClassStaticSetter
-                } else {
-                    Named::ClassSetter
-                })
+                Selector::with_modifiers(Kind::ClassSetter, setter.modifiers())
             }
             AnyJsClassMember::TsSetterSignatureClassMember(setter) => {
-                let is_static = setter
-                    .modifiers()
-                    .iter()
-                    .any(|modifier| modifier.as_js_static_modifier().is_some());
-                Some(if is_static {
-                    Named::ClassStaticSetter
-                } else {
-                    Named::ClassSetter
-                })
+                Selector::with_modifiers(Kind::ClassSetter, setter.modifiers())
             }
-        }
+        };
+        // Ignore explicitly overrided members
+        (!modifiers.contains(Modifier::Override)).then_some(Selector {
+            kind,
+            modifiers,
+            scope,
+        })
     }
 
-    fn from_binding_declaration(decl: &AnyJsBindingDeclaration) -> Option<Named> {
+    fn from_binding_declaration(decl: &AnyJsBindingDeclaration) -> Option<Selector> {
         match decl {
             AnyJsBindingDeclaration::JsArrayBindingPatternElement(_)
             | AnyJsBindingDeclaration::JsArrayBindingPatternRestElement(_)
@@ -810,41 +910,39 @@ impl Named {
             | AnyJsBindingDeclaration::JsObjectBindingPatternRest(_) => {
                 Self::from_parent_binding_pattern_declaration(decl.parent_binding_pattern_declaration()?)
             }
-            AnyJsBindingDeclaration::JsObjectBindingPatternShorthandProperty(_) => {
-                Some(Named::DestructuredObjectMember)
-            }
             AnyJsBindingDeclaration::JsVariableDeclarator(var) => {
-                Named::from_variable_declarator(var)
+                Selector::from_variable_declarator(var, Scope::from_declaration(decl))
             }
             AnyJsBindingDeclaration::JsArrowFunctionExpression(_)
             | AnyJsBindingDeclaration::JsBogusParameter(_)
             | AnyJsBindingDeclaration::JsFormalParameter(_)
-            | AnyJsBindingDeclaration::JsRestParameter(_) => Some(Named::FunctionParameter),
-            AnyJsBindingDeclaration::JsCatchDeclaration(_) => Some(Named::CatchParameter),
-            AnyJsBindingDeclaration::TsPropertyParameter(_) => Some(Named::ParameterProperty),
-            AnyJsBindingDeclaration::TsIndexSignatureParameter(_) => Some(Named::IndexParameter),
-            AnyJsBindingDeclaration::JsNamespaceImportSpecifier(_) => Some(Named::ImportNamespace),
+            | AnyJsBindingDeclaration::JsRestParameter(_) => Some(Kind::FunctionParameter.into()),
+            AnyJsBindingDeclaration::JsCatchDeclaration(_) => Some(Kind::CatchParameter.into()),
+            AnyJsBindingDeclaration::TsPropertyParameter(_) => Some(Kind::ClassProperty.into()),
+            AnyJsBindingDeclaration::TsIndexSignatureParameter(_) => Some(Kind::IndexParameter.into()),
+            AnyJsBindingDeclaration::JsNamespaceImportSpecifier(_) => Some(Selector::with_cope(Kind::ImportNamespace, Scope::Global)),
             AnyJsBindingDeclaration::JsFunctionDeclaration(_)
             | AnyJsBindingDeclaration::JsFunctionExpression(_)
             | AnyJsBindingDeclaration::JsFunctionExportDefaultDeclaration(_)
             | AnyJsBindingDeclaration::TsDeclareFunctionDeclaration(_)
             | AnyJsBindingDeclaration::TsDeclareFunctionExportDefaultDeclaration(_) => {
-                Some(Named::Function)
+                Some(Selector::with_cope(Kind::Function, Scope::from_declaration(decl)))
             }
             AnyJsBindingDeclaration::TsImportEqualsDeclaration(_)
             | AnyJsBindingDeclaration::JsDefaultImportSpecifier(_)
-            | AnyJsBindingDeclaration::JsNamedImportSpecifier(_) => Some(Named::ImportAlias),
-            AnyJsBindingDeclaration::TsModuleDeclaration(_) => Some(Named::Namespace),
-            AnyJsBindingDeclaration::TsTypeAliasDeclaration(_) => Some(Named::TypeAlias),
+            | AnyJsBindingDeclaration::JsNamedImportSpecifier(_) => Some(Selector::with_cope(Kind::ImportAlias, Scope::Global)),
+            AnyJsBindingDeclaration::TsModuleDeclaration(_) => Some(Selector::with_cope(Kind::Namespace, Scope::Global)),
+            AnyJsBindingDeclaration::TsTypeAliasDeclaration(_) => Some(Selector::with_cope(Kind::TypeAlias, Scope::from_declaration(decl))),
             AnyJsBindingDeclaration::JsClassDeclaration(_)
             | AnyJsBindingDeclaration::JsClassExpression(_)
-            | AnyJsBindingDeclaration::JsClassExportDefaultDeclaration(_) => Some(Named::Class),
-            AnyJsBindingDeclaration::TsInterfaceDeclaration(_) => Some(Named::Interface),
-            AnyJsBindingDeclaration::TsEnumDeclaration(_) => Some(Named::Enum),
-            AnyJsBindingDeclaration::JsShorthandNamedImportSpecifier(_) => {
-                Some(Named::Import)
-            }
-            AnyJsBindingDeclaration::JsBogusNamedImportSpecifier(_)
+            | AnyJsBindingDeclaration::JsClassExportDefaultDeclaration(_) => {
+                Some(Selector::with_cope(Kind::Class, Scope::from_declaration(decl)))
+            },
+            AnyJsBindingDeclaration::TsInterfaceDeclaration(_) => Some(Selector::with_cope(Kind::Interface, Scope::from_declaration(decl))),
+            AnyJsBindingDeclaration::TsEnumDeclaration(_) => Some(Selector::with_cope(Kind::Enum, Scope::from_declaration(decl))),
+            AnyJsBindingDeclaration::JsObjectBindingPatternShorthandProperty(_)
+            | AnyJsBindingDeclaration::JsShorthandNamedImportSpecifier(_)
+            | AnyJsBindingDeclaration::JsBogusNamedImportSpecifier(_)
             // Type parameters should be handled at call site
             | AnyJsBindingDeclaration::TsInferType(_)
             | AnyJsBindingDeclaration::TsMappedType(_)
@@ -852,178 +950,585 @@ impl Named {
         }
     }
 
-    fn from_parent_binding_pattern_declaration(decl: AnyJsBindingDeclaration) -> Option<Named> {
+    fn from_parent_binding_pattern_declaration(decl: AnyJsBindingDeclaration) -> Option<Selector> {
+        let scope = Scope::from_declaration(&decl);
         if let AnyJsBindingDeclaration::JsVariableDeclarator(declarator) = decl {
-            Named::from_variable_declarator(&declarator)
+            Selector::from_variable_declarator(&declarator, scope)
         } else {
-            Some(Named::LocalVariable)
+            Some(Selector::with_cope(Kind::VariableLike, scope))
         }
     }
 
-    fn from_variable_declarator(var: &JsVariableDeclarator) -> Option<Named> {
-        let is_top_level_level = var
-            .syntax()
-            .ancestors()
-            .find(|x| AnyJsControlFlowRoot::can_cast(x.kind()))
-            .is_some_and(|x| {
-                matches!(
-                    x.kind(),
-                    JsSyntaxKind::JS_MODULE
-                        | JsSyntaxKind::JS_SCRIPT
-                        | JsSyntaxKind::TS_MODULE_DECLARATION
-                        | JsSyntaxKind::TS_EXTERNAL_MODULE_DECLARATION
-                )
-            });
+    fn from_variable_declarator(var: &JsVariableDeclarator, scope: Scope) -> Option<Selector> {
         let var_declaration = var
             .syntax()
             .ancestors()
             .find_map(AnyJsVariableDeclaration::cast)?;
         let var_kind = var_declaration.variable_kind().ok()?;
-        Some(match (var_kind, is_top_level_level) {
-            (JsVariableKind::Const, false) => Named::LocalConst,
-            (JsVariableKind::Let, false) => Named::LocalLet,
-            (JsVariableKind::Var, false) => Named::LocalVar,
-            (JsVariableKind::Using, false) => Named::LocalUsing,
-            (JsVariableKind::Const, true) => Named::TopLevelConst,
-            (JsVariableKind::Let, true) => Named::TopLevelLet,
-            (JsVariableKind::Var, true) => Named::TopLevelVar,
-            (JsVariableKind::Using, true) => Named::LocalUsing,
-        })
+        let kind = match var_kind {
+            JsVariableKind::Const => Kind::Const,
+            JsVariableKind::Let => Kind::Let,
+            JsVariableKind::Using => Kind::Using,
+            JsVariableKind::Var => Kind::Var,
+        };
+        Some(Selector::with_cope(kind, scope))
     }
 
-    fn from_object_member(member: &AnyJsObjectMember) -> Option<Named> {
+    fn from_object_member(member: &AnyJsObjectMember) -> Option<Selector> {
         match member {
             AnyJsObjectMember::JsBogusMember(_) | AnyJsObjectMember::JsSpread(_) => None,
-            AnyJsObjectMember::JsGetterObjectMember(_) => Some(Named::ObjectGetter),
-            AnyJsObjectMember::JsMethodObjectMember(_) => Some(Named::ObjectMethod),
+            AnyJsObjectMember::JsGetterObjectMember(_) => Some(Kind::ObjectLiteralGetter.into()),
+            AnyJsObjectMember::JsMethodObjectMember(_) => Some(Kind::ObjectLiteralMethod.into()),
             AnyJsObjectMember::JsPropertyObjectMember(_)
-            | AnyJsObjectMember::JsShorthandPropertyObjectMember(_) => Some(Named::ObjectProperty),
-            AnyJsObjectMember::JsSetterObjectMember(_) => Some(Named::ObjectSetter),
+            | AnyJsObjectMember::JsShorthandPropertyObjectMember(_) => {
+                Some(Kind::ObjectLiteralProperty.into())
+            }
+            AnyJsObjectMember::JsSetterObjectMember(_) => Some(Kind::ObjectLiteralSetter.into()),
         }
     }
 
-    fn from_type_member(member: &AnyTsTypeMember) -> Option<Named> {
+    fn from_type_member(member: &AnyTsTypeMember) -> Option<Selector> {
         match member {
             AnyTsTypeMember::JsBogusMember(_)
             | AnyTsTypeMember::TsCallSignatureTypeMember(_)
             | AnyTsTypeMember::TsConstructSignatureTypeMember(_) => None,
-            AnyTsTypeMember::TsIndexSignatureTypeMember(_) => Some(Named::IndexParameter),
-            AnyTsTypeMember::TsGetterSignatureTypeMember(_) => Some(Named::TypeGetter),
-            AnyTsTypeMember::TsMethodSignatureTypeMember(_) => Some(Named::TypeMethod),
+            AnyTsTypeMember::TsIndexSignatureTypeMember(_) => Some(Kind::IndexParameter.into()),
+            AnyTsTypeMember::TsGetterSignatureTypeMember(_) => Some(Kind::TypeGetter.into()),
+            AnyTsTypeMember::TsMethodSignatureTypeMember(_) => Some(Kind::TypeMethod.into()),
             AnyTsTypeMember::TsPropertySignatureTypeMember(property) => {
                 Some(if property.readonly_token().is_some() {
-                    Named::TypeReadonlyProperty
+                    Selector::with_modifiers(Kind::TypeProperty, Modifier::Readonly)
                 } else {
-                    Named::TypeProperty
+                    Kind::TypeProperty.into()
                 })
             }
-            AnyTsTypeMember::TsSetterSignatureTypeMember(_) => Some(Named::TypeSetter),
+            AnyTsTypeMember::TsSetterSignatureTypeMember(_) => Some(Kind::TypeSetter.into()),
         }
     }
 
-    /// Returns the list of allowed [Case] for `self`.
+    /// Returns the list of default [Case] for `self`.
     /// The preferred case comes first in the list.
-    fn allowed_cases(self, options: &NamingConventionOptions) -> SmallVec<[Case; 3]> {
-        match self {
-            Named::CatchParameter
-            | Named::ClassGetter
-            | Named::ClassMethod
-            | Named::ClassProperty
-            | Named::ClassSetter
-            | Named::ClassStaticMethod
-            | Named::ClassStaticSetter
-            | Named::IndexParameter
-            | Named::ObjectGetter
-            | Named::ObjectMethod
-            | Named::ObjectProperty
-            | Named::ObjectSetter
-            | Named::ParameterProperty
-            | Named::TypeMethod
-            | Named::TypeProperty
-            | Named::TypeSetter => SmallVec::from_slice(&[Case::Camel]),
-            Named::Class
-            | Named::Enum
-            | Named::Interface
-            | Named::TypeAlias
-            | Named::TypeParameter => SmallVec::from_slice(&[Case::Pascal]),
-            Named::ClassStaticGetter
-            | Named::ClassStaticProperty
-            | Named::TypeReadonlyProperty
-            | Named::TypeGetter => SmallVec::from_slice(&[Case::Camel, Case::Constant]),
-            Named::EnumMember => SmallVec::from_slice(&[options.enum_member_case.into()]),
-            Named::ExportAlias | Named::ImportAlias | Named::TopLevelConst | Named::TopLevelVar => {
-                SmallVec::from_slice(&[Case::Camel, Case::Pascal, Case::Constant])
+    fn default_convention(self, options: &NamingConventionOptions) -> Convention {
+        let kind = self.kind;
+        match kind {
+            Kind::TypeProperty if self.modifiers.contains(Modifier::Readonly) => Convention {
+                selector: Selector::with_modifiers(self.kind, Modifier::Readonly),
+                matching: Some(DEFAULT_MATCH.clone()),
+                formats: Formats(Case::Camel | Case::Constant),
+            },
+            Kind::TypeGetter => Convention {
+                selector: kind.into(),
+                matching: Some(DEFAULT_MATCH.clone()),
+                formats: Formats(Case::Camel | Case::Constant),
+            },
+            Kind::VariableLike | Kind::Const | Kind::Var
+                if self.scope.is_compatible_with(Scope::Global) =>
+            {
+                Convention {
+                    selector: Selector::with_cope(kind, Scope::Global),
+                    matching: Some(DEFAULT_MATCH.clone()),
+                    formats: Formats(Case::Camel | Case::Pascal | Case::Constant),
+                }
             }
-            Named::DestructuredObjectMember | Named::Export | Named::Import => SmallVec::new(),
-            Named::ExportNamespace
-            | Named::Function
-            | Named::FunctionParameter
-            | Named::ImportNamespace
-            | Named::LocalConst
-            | Named::LocalLet
-            | Named::LocalVar
-            | Named::LocalVariable
-            | Named::LocalUsing
-            | Named::Namespace
-            | Named::TopLevelLet => SmallVec::from_slice(&[Case::Camel, Case::Pascal]),
+            Kind::Any | Kind::ExportAlias | Kind::ImportAlias => Convention {
+                selector: kind.into(),
+                matching: Some(DEFAULT_MATCH.clone()),
+                formats: Formats(Case::Camel | Case::Pascal | Case::Constant),
+            },
+            Kind::ClassProperty | Kind::ClassGetter
+                if self.modifiers.contains(Modifier::Static) =>
+            {
+                Convention {
+                    selector: Selector::with_modifiers(kind, Modifier::Static),
+                    matching: Some(DEFAULT_MATCH.clone()),
+                    formats: Formats(Case::Camel | Case::Constant),
+                }
+            }
+            Kind::MemberLike
+            | Kind::CatchParameter
+            | Kind::ClassGetter
+            | Kind::ClassMethod
+            | Kind::ClassProperty
+            | Kind::ClassSetter
+            | Kind::IndexParameter
+            | Kind::ObjectLiteralGetter
+            | Kind::ObjectLiteralMethod
+            | Kind::ObjectLiteralProperty
+            | Kind::ObjectLiteralSetter
+            | Kind::TypeMethod
+            | Kind::TypeProperty
+            | Kind::TypeSetter
+            | Kind::Using => Convention {
+                selector: kind.into(),
+                matching: Some(DEFAULT_MATCH.clone()),
+                formats: Formats(Case::Camel.into()),
+            },
+            Kind::TypeLike
+            | Kind::Class
+            | Kind::Enum
+            | Kind::Interface
+            | Kind::TypeAlias
+            | Kind::TypeParameter => Convention {
+                selector: kind.into(),
+                matching: Some(DEFAULT_MATCH.clone()),
+                formats: Formats(Case::Pascal.into()),
+            },
+            Kind::EnumMember => Convention {
+                selector: kind.into(),
+                matching: Some(DEFAULT_MATCH.clone()),
+                formats: Formats(Case::from(options.enum_member_case).into()),
+            },
+            Kind::VariableLike | Kind::Const | Kind::Var | Kind::Let => Convention {
+                selector: kind.into(),
+                matching: Some(DEFAULT_MATCH.clone()),
+                formats: Formats(Case::Camel | Case::Pascal),
+            },
+            Kind::Function
+            | Kind::ExportNamespace
+            | Kind::ImportNamespace
+            | Kind::Namespace
+            | Kind::NamespaceLike
+            | Kind::FunctionParameter => Convention {
+                selector: kind.into(),
+                matching: Some(DEFAULT_MATCH.clone()),
+                formats: Formats(Case::Camel | Case::Pascal),
+            },
         }
     }
+
+    fn contains(&self, other: Selector) -> bool {
+        self.kind.contains(other.kind)
+            && self.modifiers.contains(other.modifiers.0)
+            && self.scope.is_compatible_with(other.scope)
+    }
+}
+
+lazy_static::lazy_static! {
+    static ref DEFAULT_MATCH: RestrictedRegex = "^[_$]*(.*?)[_$]*$".try_into().unwrap();
 }
 
-impl std::fmt::Display for Named {
+#[derive(
+    Clone,
+    Copy,
+    Debug,
+    Default,
+    Deserializable,
+    Eq,
+    Hash,
+    PartialEq,
+    serde::Deserialize,
+    serde::Serialize,
+)]
+#[cfg_attr(feature = "schemars", derive(JsonSchema))]
+#[serde(rename_all = "camelCase")]
+pub enum Kind {
+    #[default]
+    Any,
+    CatchParameter,
+    Class,
+    ClassGetter,
+    ClassMethod,
+    ClassProperty,
+    ClassSetter,
+    Const,
+    Enum,
+    EnumMember,
+    ExportNamespace,
+    Function,
+    ImportNamespace,
+    IndexParameter,
+    Interface,
+    Let,
+    ExportAlias,
+    ImportAlias,
+    MemberLike,
+    Namespace,
+    NamespaceLike,
+    ObjectLiteralGetter,
+    ObjectLiteralMethod,
+    ObjectLiteralProperty,
+    ObjectLiteralSetter,
+    FunctionParameter,
+    TypeAlias,
+    TypeGetter,
+    TypeLike,
+    TypeMethod,
+    TypeParameter,
+    TypeProperty,
+    TypeSetter,
+    Using,
+    Var,
+    VariableLike,
+}
+impl Kind {
+    pub fn contains(self, other: Self) -> bool {
+        self == other
+            || matches!(
+                (other, self),
+                (
+                    Self::VariableLike,
+                    Self::CatchParameter
+                        | Self::Const
+                        | Self::ExportAlias
+                        | Self::ImportAlias
+                        | Self::IndexParameter
+                        | Self::Let
+                        | Self::FunctionParameter
+                        | Self::Using
+                        | Self::Var,
+                ) | (
+                    Self::MemberLike,
+                    Self::ClassGetter
+                        | Self::ClassMethod
+                        | Self::ClassProperty
+                        | Self::ClassSetter
+                        | Self::ObjectLiteralGetter
+                        | Self::ObjectLiteralMethod
+                        | Self::ObjectLiteralProperty
+                        | Self::ObjectLiteralSetter
+                        | Self::TypeGetter
+                        | Self::TypeMethod
+                        | Self::TypeParameter
+                        | Self::TypeProperty
+                        | Self::TypeSetter
+                ) | (
+                    Self::NamespaceLike,
+                    Self::ExportNamespace | Self::ImportNamespace | Self::Namespace
+                ) | (
+                    Self::TypeLike,
+                    Self::Class
+                        | Self::Enum
+                        | Self::EnumMember
+                        | Self::Interface
+                        | Self::TypeAlias
+                        | Self::TypeParameter
+                ) | (Self::Any, _)
+            )
+    }
+}
+impl std::fmt::Display for Kind {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         let repr = match self {
-            Named::CatchParameter => "catch parameter",
-            Named::Class => "class",
-            Named::ClassGetter => "class getter",
-            Named::ClassMethod => "class method",
-            Named::ClassProperty => "class property",
-            Named::ClassSetter => "class setter",
-            Named::ClassStaticGetter => "static getter",
-            Named::ClassStaticMethod => "static method",
-            Named::ClassStaticProperty => "static property",
-            Named::ClassStaticSetter => "static setter",
-            Named::DestructuredObjectMember => "destructured object member",
-            Named::Enum => "enum",
-            Named::EnumMember => "enum member",
-            Named::ExportAlias => "export alias",
-            Named::ExportNamespace => "export namespace",
-            Named::Export => "export source",
-            Named::Function => "function",
-            Named::FunctionParameter => "function parameter",
-            Named::ImportAlias => "import alias",
-            Named::ImportNamespace => "import namespace",
-            Named::Import => "import source",
-            Named::IndexParameter => "index parameter",
-            Named::Interface => "interface",
-            Named::LocalConst => "local const",
-            Named::LocalLet => "local let",
-            Named::LocalVar => "local var",
-            Named::LocalVariable => "local variable",
-            Named::LocalUsing => "local using",
-            Named::Namespace => "namespace",
-            Named::ObjectGetter => "object getter",
-            Named::ObjectMethod => "object method",
-            Named::ObjectProperty => "object property",
-            Named::ObjectSetter => "object setter",
-            Named::ParameterProperty => "parameter property",
-            Named::TopLevelConst => "top-level const",
-            Named::TopLevelLet => "top-level let",
-            Named::TopLevelVar => "top-level var",
-            Named::TypeAlias => "type alias",
-            Named::TypeGetter => "getter",
-            Named::TypeMethod => "method",
-            Named::TypeProperty => "property",
-            Named::TypeReadonlyProperty => "readonly property",
-            Named::TypeSetter => "setter",
-            Named::TypeParameter => "type parameter",
+            Self::Any => "declaration",
+            Self::CatchParameter => "catch parameter",
+            Self::Class => "class",
+            Self::ClassGetter => "class getter",
+            Self::ClassMethod => "class method",
+            Self::ClassProperty => "class property",
+            Self::ClassSetter => "class setter",
+            Self::Const => "const",
+            Self::Enum => "enum",
+            Self::EnumMember => "enum member",
+            Self::ExportAlias => "export alias",
+            Self::ExportNamespace => "export namespace",
+            Self::Function => "function",
+            Self::ImportAlias => "import alias",
+            Self::ImportNamespace => "import namespace",
+            Self::IndexParameter => "index parameter",
+            Self::Interface => "interface",
+            Self::Let => "let",
+            Self::MemberLike => "member",
+            Self::Namespace => "namespace",
+            Self::NamespaceLike => "namespace",
+            Self::ObjectLiteralGetter => "object getter",
+            Self::ObjectLiteralMethod => "object method",
+            Self::ObjectLiteralProperty => "object property",
+            Self::ObjectLiteralSetter => "object setter",
+            Self::FunctionParameter => "function parameter",
+            Self::TypeAlias => "type alias",
+            Self::TypeGetter => "getter",
+            Self::TypeLike => "type",
+            Self::TypeMethod => "method",
+            Self::TypeParameter => "type parameter",
+            Self::TypeProperty => "property",
+            Self::TypeSetter => "setter",
+            Self::Using => "using",
+            Self::Var => "var",
+            Self::VariableLike => "variable",
         };
         write!(f, "{}", repr)
     }
 }
 
-/// trim underscores and dollar signs from `name`.
-fn trim_underscore_dollar(name: &str) -> &str {
-    name.trim_start_matches(|c| c == '_' || c == '$')
-        .trim_end_matches(|c| c == '_' || c == '$')
+#[derive(Debug, Deserializable, Copy, Clone, serde::Deserialize, serde::Serialize)]
+#[cfg_attr(feature = "schemars", derive(JsonSchema))]
+#[serde(rename_all = "camelCase")]
+#[repr(u16)]
+enum RestrictedModifier {
+    Abstract = Modifier::Abstract as u16,
+    Private = Modifier::Private as u16,
+    Protected = Modifier::Protected as u16,
+    Readonly = Modifier::Readonly as u16,
+    Static = Modifier::Static as u16,
+}
+
+impl From<RestrictedModifier> for Modifier {
+    fn from(modifier: RestrictedModifier) -> Self {
+        match modifier {
+            RestrictedModifier::Abstract => Modifier::Abstract,
+            RestrictedModifier::Private => Modifier::Private,
+            RestrictedModifier::Protected => Modifier::Protected,
+            RestrictedModifier::Readonly => Modifier::Readonly,
+            RestrictedModifier::Static => Modifier::Static,
+        }
+    }
+}
+impl From<Modifier> for RestrictedModifier {
+    fn from(modifier: Modifier) -> Self {
+        match modifier {
+            Modifier::Abstract => RestrictedModifier::Abstract,
+            Modifier::Private => RestrictedModifier::Private,
+            Modifier::Protected => RestrictedModifier::Protected,
+            Modifier::Readonly => RestrictedModifier::Readonly,
+            Modifier::Static => RestrictedModifier::Static,
+            _ => unreachable!(""),
+        }
+    }
+}
+
+#[derive(Debug, Deserializable, Default, serde::Deserialize, serde::Serialize)]
+struct RestrictedModifierList(SmallVec<[RestrictedModifier; 4]>);
+
+#[derive(
+    Debug,
+    Copy,
+    Default,
+    Deserializable,
+    Clone,
+    Hash,
+    Eq,
+    PartialEq,
+    serde::Deserialize,
+    serde::Serialize,
+)]
+#[serde(from = "RestrictedModifierList", into = "RestrictedModifierList")]
+struct Modifiers(BitFlags<Modifier>);
+
+#[cfg(feature = "schemars")]
+impl JsonSchema for Modifiers {
+    fn schema_name() -> String {
+        "Modifiers".to_string()
+    }
+
+    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
+        <std::collections::HashSet<RestrictedModifier>>::json_schema(gen)
+    }
+}
+impl Deref for Modifiers {
+    type Target = BitFlags<Modifier>;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl From<Modifier> for Modifiers {
+    fn from(value: Modifier) -> Self {
+        Modifiers(value.into())
+    }
+}
+impl From<Modifiers> for RestrictedModifierList {
+    fn from(value: Modifiers) -> Self {
+        Self(value.into_iter().map(|modifier| modifier.into()).collect())
+    }
+}
+impl From<RestrictedModifierList> for Modifiers {
+    fn from(value: RestrictedModifierList) -> Self {
+        Self(
+            value
+                .0
+                .into_iter()
+                .map(Modifier::from)
+                .fold(BitFlags::empty(), |acc, m| acc | m),
+        )
+    }
+}
+impl From<JsMethodModifierList> for Modifiers {
+    fn from(value: JsMethodModifierList) -> Self {
+        Modifiers((&value).into())
+    }
+}
+impl From<JsPropertyModifierList> for Modifiers {
+    fn from(value: JsPropertyModifierList) -> Self {
+        Modifiers((&value).into())
+    }
+}
+impl From<TsMethodSignatureModifierList> for Modifiers {
+    fn from(value: TsMethodSignatureModifierList) -> Self {
+        Modifiers((&value).into())
+    }
+}
+impl From<TsPropertySignatureModifierList> for Modifiers {
+    fn from(value: TsPropertySignatureModifierList) -> Self {
+        Modifiers((&value).into())
+    }
+}
+impl std::fmt::Display for Modifiers {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        for value in self.0.iter() {
+            write!(f, "{} ", value)?;
+        }
+        Ok(())
+    }
+}
+
+#[derive(
+    Debug,
+    Copy,
+    Default,
+    Deserializable,
+    Clone,
+    Hash,
+    Eq,
+    PartialEq,
+    serde::Deserialize,
+    serde::Serialize,
+)]
+#[cfg_attr(feature = "schemars", derive(JsonSchema))]
+#[serde(rename_all = "camelCase")]
+pub enum Scope {
+    #[default]
+    Any,
+    Global,
+}
+
+impl Scope {
+    fn from_declaration(node: &AnyJsBindingDeclaration) -> Scope {
+        let is_top_level = node
+            .syntax()
+            .ancestors()
+            .skip(1)
+            .find(|x| AnyJsControlFlowRoot::can_cast(x.kind()))
+            .is_some_and(|x| {
+                matches!(
+                    x.kind(),
+                    JsSyntaxKind::JS_MODULE
+                        | JsSyntaxKind::JS_SCRIPT
+                        | JsSyntaxKind::TS_MODULE_DECLARATION
+                        | JsSyntaxKind::TS_EXTERNAL_MODULE_DECLARATION
+                )
+            });
+        if is_top_level {
+            Scope::Global
+        } else {
+            Scope::Any
+        }
+    }
+
+    fn is_compatible_with(self, scope: Scope) -> bool {
+        matches!(scope, Self::Any) || self == scope
+    }
+}
+impl std::fmt::Display for Scope {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let repr = match self {
+            Self::Any => "",
+            Self::Global => "global ",
+        };
+        write!(f, "{repr}")
+    }
+}
+
+/// Supported cases.
+#[derive(
+    Clone,
+    Copy,
+    Debug,
+    Default,
+    Deserializable,
+    Eq,
+    Hash,
+    PartialEq,
+    serde::Deserialize,
+    serde::Serialize,
+)]
+#[cfg_attr(feature = "schemars", derive(JsonSchema))]
+pub enum Format {
+    /// camelCase
+    #[serde(rename = "camelCase")]
+    Camel,
+
+    /// CONSTANT_CASE
+    #[serde(rename = "CONSTANT_CASE")]
+    Constant,
+
+    /// PascalCase
+    #[serde(rename = "PascalCase")]
+    #[default]
+    Pascal,
+
+    /// snake_case
+    #[serde(rename = "snake_case")]
+    Snake,
+
+    /// any case
+    #[serde(rename = "unknown")]
+    Unknown,
+}
+impl From<Format> for Case {
+    fn from(value: Format) -> Self {
+        match value {
+            Format::Camel => Case::Camel,
+            Format::Constant => Case::Constant,
+            Format::Pascal => Case::Pascal,
+            Format::Snake => Case::Snake,
+            Format::Unknown => Case::Unknown,
+        }
+    }
+}
+impl TryFrom<Case> for Format {
+    type Error = &'static str;
+
+    fn try_from(value: Case) -> Result<Self, Self::Error> {
+        match value {
+            Case::Camel => Ok(Format::Camel),
+            Case::Constant => Ok(Format::Constant),
+            Case::Pascal => Ok(Format::Pascal),
+            Case::Snake => Ok(Format::Snake),
+            Case::Unknown => Ok(Format::Unknown),
+            Case::Kebab | Case::Lower | Case::NumberableCapital | Case::Uni | Case::Upper => {
+                Err("Unsupported case")
+            }
+        }
+    }
+}
+
+#[derive(
+    Clone, Debug, Default, Deserializable, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize,
+)]
+struct FormatList(SmallVec<[Format; 4]>);
+impl From<Formats> for FormatList {
+    fn from(value: Formats) -> Self {
+        FormatList(
+            value
+                .0
+                .into_iter()
+                .filter_map(|case| case.try_into().ok())
+                .collect(),
+        )
+    }
+}
+
+#[derive(
+    Clone, Debug, Default, Deserializable, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize,
+)]
+#[serde(from = "FormatList", into = "FormatList")]
+pub struct Formats(Cases);
+impl From<FormatList> for Formats {
+    fn from(value: FormatList) -> Self {
+        Self(value.0.into_iter().map(|format| format.into()).collect())
+    }
+}
+#[cfg(feature = "schemars")]
+impl JsonSchema for Formats {
+    fn schema_name() -> String {
+        "Formats".to_string()
+    }
+    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
+        <std::collections::HashSet<Format>>::json_schema(gen)
+    }
+}
+impl Deref for Formats {
+    type Target = Cases;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
 }
diff --git a/crates/biome_js_analyze/src/utils.rs b/crates/biome_js_analyze/src/utils.rs
index 419519b13e28..7d3b02a60286 100644
--- a/crates/biome_js_analyze/src/utils.rs
+++ b/crates/biome_js_analyze/src/utils.rs
@@ -3,6 +3,7 @@ use biome_rowan::{AstNode, Direction, WalkEvent};
 use std::iter;
 
 pub mod batch;
+pub mod regex;
 pub mod rename;
 #[cfg(test)]
 pub mod tests;
diff --git a/crates/biome_js_analyze/src/utils/regex.rs b/crates/biome_js_analyze/src/utils/regex.rs
new file mode 100644
index 000000000000..347b1f2c5e14
--- /dev/null
+++ b/crates/biome_js_analyze/src/utils/regex.rs
@@ -0,0 +1,175 @@
+use std::ops::Deref;
+
+use biome_deserialize_macros::Deserializable;
+
+/// A restricted regular expression only supports widespread syntaxes:
+///
+/// - Greedy quantifiers `*`, `?`, `+`, `{n}`, `{n,m}`, `{n,}`, `{m}`
+/// - Non-greedy quantifiers `*?`, `??`, `+?`, `{n}?`, `{n,m}?`, `{n,}?`, `{m}?`
+/// - Anchros `^`, `$`
+/// - An ycharacter matcher `.`
+/// - Character classes `[a-z]`, `[xyz]`, `[^a-z]`
+/// - Alternations `|`
+/// - Capturing groups `()`
+/// - Non-capturing groups `(?:)`
+/// - A limited set of escaped characters including all regex special characters
+///   and regular string escape characters `\f`, `\n`, `\r`, `\t`, `\v`
+///
+/// A restricted regular expression is implictly delimited by the anchors `^` and `$`.
+#[derive(Clone, Debug, Deserializable, serde::Deserialize, serde::Serialize)]
+#[serde(try_from = "String", into = "String")]
+pub struct RestrictedRegex(regex::Regex);
+impl RestrictedRegex {
+    /// Similar to `Self::as_str`, but returns the original regex representation,
+    /// without the implicit anchors and the implicit group.
+    pub fn as_source(&self) -> &str {
+        let repr = self.0.as_str();
+        debug_assert!(repr.starts_with("^(?:"));
+        debug_assert!(repr.ends_with(")$"));
+        &repr[4..(repr.len() - 2)]
+    }
+}
+impl From<RestrictedRegex> for String {
+    fn from(value: RestrictedRegex) -> Self {
+        value.into()
+    }
+}
+impl Deref for RestrictedRegex {
+    type Target = regex::Regex;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl TryFrom<String> for RestrictedRegex {
+    type Error = regex::Error;
+
+    fn try_from(value: String) -> Result<Self, Self::Error> {
+        is_restricted_regex(&value)?;
+        regex::Regex::new(&format!("^(?:{value})$")).map(RestrictedRegex)
+    }
+}
+impl TryFrom<&str> for RestrictedRegex {
+    type Error = regex::Error;
+
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
+        is_restricted_regex(value)?;
+        regex::Regex::new(&format!("^(?:{value})$")).map(RestrictedRegex)
+    }
+}
+#[cfg(feature = "schemars")]
+impl schemars::JsonSchema for RestrictedRegex {
+    fn schema_name() -> String {
+        "Regex".to_string()
+    }
+
+    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
+        String::json_schema(gen)
+    }
+}
+impl Eq for RestrictedRegex {}
+impl PartialEq for RestrictedRegex {
+    fn eq(&self, other: &Self) -> bool {
+        self.0.as_str() == other.0.as_str()
+    }
+}
+
+/// Rteurns an error if `pattern` follows the restricted regular expression syntax.
+fn is_restricted_regex(pattern: &str) -> Result<(), regex::Error> {
+    let mut it = pattern.chars();
+    let mut is_in_char_class = false;
+    while let Some(c) = it.next() {
+        match c {
+            '\\' => {
+                // Accept a restrictive set of escape sequence
+                // We keep only escaped chars that behave identically
+                // in unicode-enabled and unicode-disabled RegExes.
+                if let Some(c) = it.next() {
+                    if !matches!(
+                        c,
+                        '^' | '|'
+                            | '*'
+                            | '?'
+                            | '{'
+                            | '}'
+                            | '['
+                            | ']'
+                            | '-'
+                            | '$'
+                            | 'f'
+                            | 'n'
+                            | 'r'
+                            | 't'
+                            | 'v'
+                    ) {
+                        // Escape sequences https://docs.rs/regex/latest/regex/#escape-sequences
+                        // and Perl char classes https://docs.rs/regex/latest/regex/#perl-character-classes-unicode-friendly
+                        return Err(regex::Error::Syntax(format!(
+                            "Escape sequence \\{c} is not supported."
+                        )));
+                    }
+                }
+            }
+            '[' if is_in_char_class => {
+                return Err(regex::Error::Syntax(
+                    "Nested character class are not supported.".to_string(),
+                ));
+            }
+            '[' => {
+                is_in_char_class = true;
+            }
+            ']' => {
+                is_in_char_class = false;
+            }
+            '&' | '~' | '-' if is_in_char_class => {
+                if it.next() == Some(c) {
+                    return Err(regex::Error::Syntax(format!(
+                        "Character class operator {c}{c} is not supported."
+                    )));
+                }
+            }
+            '(' => {
+                if it.next() == Some('?') {
+                    match it.next() {
+                        Some('P' | '=' | '!' | '<') => {
+                            return if c == 'P'
+                                || (c == '<' && !matches!(it.next(), Some('=' | '!')))
+                            {
+                                Err(regex::Error::Syntax(
+                                    "Named groups `(?<NAME>)` are not supported.".to_string(),
+                                ))
+                            } else {
+                                Err(regex::Error::Syntax(format!(
+                                    "Assertions `(?{c})` are not supported."
+                                )))
+                            };
+                        }
+                        Some(':') => {}
+                        _ => {
+                            return Err(regex::Error::Syntax(
+                                "Group flags `(?flags:)` are not supported.".to_string(),
+                            ));
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test() {
+        assert!(is_restricted_regex("").is_ok());
+        assert!(is_restricted_regex("^$").is_ok());
+        assert!(is_restricted_regex("^abc$").is_ok());
+        assert!(is_restricted_regex("(?:a)(.+)z").is_ok());
+        assert!(is_restricted_regex("[A-Z][^a-z]").is_ok());
+        assert!(is_restricted_regex(r"\n\t\v\f").is_ok());
+    }
+}
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCatchParameter.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCatchParameter.js.snap
index 331d888df092..e6371f56d754 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCatchParameter.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCatchParameter.js.snap
@@ -25,8 +25,6 @@ invalidCatchParameter.js:1:14 lint/style/useNamingConvention  FIXABLE  ━━━
     2 │ 
     3 │ try {} catch(SpecificError) {}
   
-  i The name could be renamed to `e`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     1   │ - try·{}·catch(E)·{}
@@ -49,8 +47,6 @@ invalidCatchParameter.js:3:14 lint/style/useNamingConvention  FIXABLE  ━━━
     4 │ 
     5 │ try {} catch(specific_error) {}
   
-  i The name could be renamed to `specificError`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     1 1 │   try {} catch(E) {}
@@ -75,8 +71,6 @@ invalidCatchParameter.js:5:14 lint/style/useNamingConvention  FIXABLE  ━━━
     6 │ 
     7 │ try {} catch(SPECIFIC_ERROR) {}
   
-  i The name could be renamed to `specificError`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     3 3 │   try {} catch(SpecificError) {}
@@ -100,8 +94,6 @@ invalidCatchParameter.js:7:14 lint/style/useNamingConvention  FIXABLE  ━━━
       │              ^^^^^^^^^^^^^^
     8 │ 
   
-  i The name could be renamed to `specificError`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     5 5 │   try {} catch(specific_error) {}
@@ -112,5 +104,3 @@ invalidCatchParameter.js:7:14 lint/style/useNamingConvention  FIXABLE  ━━━
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClass.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClass.js.snap
index 0c04ae7faff4..c4e212ebf80c 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClass.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClass.js.snap
@@ -26,8 +26,6 @@ invalidClass.js:1:7 lint/style/useNamingConvention  FIXABLE  ━━━━━━
     2 │ 
     3 │ class camelCase {}
   
-  i The name could be renamed to `C`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
     1   │ - class·c·{}
@@ -50,8 +48,6 @@ invalidClass.js:3:7 lint/style/useNamingConvention  FIXABLE  ━━━━━━
     4 │ 
     5 │ export default class default_class {}
   
-  i The name could be renamed to `CamelCase`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
     1 1 │   class c {}
@@ -76,8 +72,6 @@ invalidClass.js:5:22 lint/style/useNamingConvention ━━━━━━━━━
     6 │ 
     7 │ const x = class CLASS_EXPRESSION {}
   
-  i The name could be renamed to `DefaultClass`.
-  
 
 ```
 
@@ -93,8 +87,6 @@ invalidClass.js:7:17 lint/style/useNamingConvention  FIXABLE  ━━━━━━
     8 │ 
     9 │ class Unknown_Style {}
   
-  i The name could be renamed to `ClassExpression`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
     5 5 │   export default class default_class {}
@@ -117,8 +109,6 @@ invalidClass.js:9:7 lint/style/useNamingConvention  FIXABLE  ━━━━━━
   > 9 │ class Unknown_Style {}
       │       ^^^^^^^^^^^^^
   
-  i The name could be renamed to `UnknownStyle`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
     7 7 │   const x = class CLASS_EXPRESSION {}
@@ -128,5 +118,3 @@ invalidClass.js:9:7 lint/style/useNamingConvention  FIXABLE  ━━━━━━
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassGetter.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassGetter.js.snap
index 6711e0afa42f..9d9bc33ee8b9 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassGetter.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassGetter.js.snap
@@ -39,8 +39,6 @@ invalidClassGetter.js:2:9 lint/style/useNamingConvention ━━━━━━━
     3 │ 
     4 │     get PROPERTY() {}
   
-  i The name could be renamed to `x`.
-  
 
 ```
 
@@ -56,8 +54,6 @@ invalidClassGetter.js:4:9 lint/style/useNamingConvention ━━━━━━━
     5 │ 
     6 │     get SpecialProperty() {}
   
-  i The name could be renamed to `property`.
-  
 
 ```
 
@@ -73,8 +69,6 @@ invalidClassGetter.js:6:9 lint/style/useNamingConvention ━━━━━━━
     7 │ 
     8 │     get special_property() {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -90,8 +84,6 @@ invalidClassGetter.js:8:9 lint/style/useNamingConvention ━━━━━━━
      9 │ 
     10 │     get Unknown_Style() {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -107,93 +99,79 @@ invalidClassGetter.js:10:9 lint/style/useNamingConvention ━━━━━━━
     11 │ 
     12 │     get #X() {}
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
 ```
-invalidClassGetter.js:12:9 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassGetter.js:12:10 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class getter name should be in camelCase.
   
     10 │     get Unknown_Style() {}
     11 │ 
   > 12 │     get #X() {}
-       │         ^^
+       │          ^
     13 │ 
     14 │     get #PROPERTY() {}
   
-  i The name could be renamed to `x`.
-  
 
 ```
 
 ```
-invalidClassGetter.js:14:9 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassGetter.js:14:10 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class getter name should be in camelCase.
   
     12 │     get #X() {}
     13 │ 
   > 14 │     get #PROPERTY() {}
-       │         ^^^^^^^^^
+       │          ^^^^^^^^
     15 │ 
     16 │     get #SpecialProperty() {}
   
-  i The name could be renamed to `property`.
-  
 
 ```
 
 ```
-invalidClassGetter.js:16:9 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassGetter.js:16:10 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class getter name should be in camelCase.
   
     14 │     get #PROPERTY() {}
     15 │ 
   > 16 │     get #SpecialProperty() {}
-       │         ^^^^^^^^^^^^^^^^
+       │          ^^^^^^^^^^^^^^^
     17 │ 
     18 │     get #special_property() {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
-invalidClassGetter.js:18:9 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassGetter.js:18:10 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class getter name should be in camelCase.
   
     16 │     get #SpecialProperty() {}
     17 │ 
   > 18 │     get #special_property() {}
-       │         ^^^^^^^^^^^^^^^^^
+       │          ^^^^^^^^^^^^^^^^
     19 │ 
     20 │     get #Unknown_Style() {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
-invalidClassGetter.js:20:9 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassGetter.js:20:10 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class getter name should be in camelCase.
   
     18 │     get #special_property() {}
     19 │ 
   > 20 │     get #Unknown_Style() {}
-       │         ^^^^^^^^^^^^^^
+       │          ^^^^^^^^^^^^^
     21 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassMethod.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassMethod.js.snap
index 36050f8a3eb5..d0bb04473fc6 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassMethod.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassMethod.js.snap
@@ -39,8 +39,6 @@ invalidClassMethod.js:2:5 lint/style/useNamingConvention ━━━━━━━
     3 │ 
     4 │     METHOD() {}
   
-  i The name could be renamed to `m`.
-  
 
 ```
 
@@ -56,15 +54,13 @@ invalidClassMethod.js:4:5 lint/style/useNamingConvention ━━━━━━━
     5 │ 
     6 │     AMethod() {}
   
-  i The name could be renamed to `method`.
-  
 
 ```
 
 ```
 invalidClassMethod.js:6:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This class method name should be in camelCase.
+  ! Two consecutive uppercase characters are not allowed in PascalCase because strictCase is set to `true`.
   
     4 │     METHOD() {}
     5 │ 
@@ -73,7 +69,8 @@ invalidClassMethod.js:6:5 lint/style/useNamingConvention ━━━━━━━
     7 │ 
     8 │     method_1() {}
   
-  i The name could be renamed to `aMethod`.
+  i If you want to use consecutive uppercase characters in PascalCase, then set the strictCase option to `false`.
+    See the rule options for more details.
   
 
 ```
@@ -90,8 +87,6 @@ invalidClassMethod.js:8:5 lint/style/useNamingConvention ━━━━━━━
      9 │ 
     10 │     Unknown_Style() {}
   
-  i The name could be renamed to `method1`.
-  
 
 ```
 
@@ -107,93 +102,82 @@ invalidClassMethod.js:10:5 lint/style/useNamingConvention ━━━━━━━
     11 │ 
     12 │     #M() {}
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
 ```
-invalidClassMethod.js:12:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassMethod.js:12:6 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class method name should be in camelCase.
   
     10 │     Unknown_Style() {}
     11 │ 
   > 12 │     #M() {}
-       │     ^^
+       │      ^
     13 │ 
     14 │     #METHOD() {}
   
-  i The name could be renamed to `m`.
-  
 
 ```
 
 ```
-invalidClassMethod.js:14:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassMethod.js:14:6 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class method name should be in camelCase.
   
     12 │     #M() {}
     13 │ 
   > 14 │     #METHOD() {}
-       │     ^^^^^^^
+       │      ^^^^^^
     15 │ 
     16 │     #AMethod() {}
   
-  i The name could be renamed to `method`.
-  
 
 ```
 
 ```
-invalidClassMethod.js:16:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassMethod.js:16:6 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This class method name should be in camelCase.
+  ! Two consecutive uppercase characters are not allowed in PascalCase because strictCase is set to `true`.
   
     14 │     #METHOD() {}
     15 │ 
   > 16 │     #AMethod() {}
-       │     ^^^^^^^^
+       │      ^^^^^^^
     17 │ 
     18 │     #method_1() {}
   
-  i The name could be renamed to `aMethod`.
+  i If you want to use consecutive uppercase characters in PascalCase, then set the strictCase option to `false`.
+    See the rule options for more details.
   
 
 ```
 
 ```
-invalidClassMethod.js:18:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassMethod.js:18:6 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class method name should be in camelCase.
   
     16 │     #AMethod() {}
     17 │ 
   > 18 │     #method_1() {}
-       │     ^^^^^^^^^
+       │      ^^^^^^^^
     19 │ 
     20 │     #Unknown_Style() {}
   
-  i The name could be renamed to `method1`.
-  
 
 ```
 
 ```
-invalidClassMethod.js:20:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassMethod.js:20:6 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class method name should be in camelCase.
   
     18 │     #method_1() {}
     19 │ 
   > 20 │     #Unknown_Style() {}
-       │     ^^^^^^^^^^^^^^
+       │      ^^^^^^^^^^^^^
     21 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassProperty.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassProperty.js.snap
index 4b30350ad40f..39328acb628e 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassProperty.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassProperty.js.snap
@@ -49,8 +49,6 @@ invalidClassProperty.js:2:5 lint/style/useNamingConvention ━━━━━━━
     3 │ 
     4 │     "Y" = 0
   
-  i The name could be renamed to `x`.
-  
 
 ```
 
@@ -62,29 +60,25 @@ invalidClassProperty.js:4:5 lint/style/useNamingConvention ━━━━━━━
     2 │     X
     3 │ 
   > 4 │     "Y" = 0
-      │     ^^^
+      │     ^
     5 │ 
     6 │     #X
   
-  i The name could be renamed to `y`.
-  
 
 ```
 
 ```
-invalidClassProperty.js:6:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassProperty.js:6:6 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class property name should be in camelCase.
   
     4 │     "Y" = 0
     5 │ 
   > 6 │     #X
-      │     ^^
+      │      ^
     7 │ 
     8 │     Initialized = 0
   
-  i The name could be renamed to `x`.
-  
 
 ```
 
@@ -100,25 +94,21 @@ invalidClassProperty.js:8:5 lint/style/useNamingConvention ━━━━━━━
      9 │ 
     10 │     #Initialized = 0
   
-  i The name could be renamed to `initialized`.
-  
 
 ```
 
 ```
-invalidClassProperty.js:10:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassProperty.js:10:6 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class property name should be in camelCase.
   
      8 │     Initialized = 0
      9 │ 
   > 10 │     #Initialized = 0
-       │     ^^^^^^^^^^^^
+       │      ^^^^^^^^^^^
     11 │ 
     12 │     PROPERTY
   
-  i The name could be renamed to `initialized`.
-  
 
 ```
 
@@ -134,25 +124,21 @@ invalidClassProperty.js:12:5 lint/style/useNamingConvention ━━━━━━
     13 │ 
     14 │     #PROPERTY
   
-  i The name could be renamed to `property`.
-  
 
 ```
 
 ```
-invalidClassProperty.js:14:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassProperty.js:14:6 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class property name should be in camelCase.
   
     12 │     PROPERTY
     13 │ 
   > 14 │     #PROPERTY
-       │     ^^^^^^^^^
+       │      ^^^^^^^^
     15 │ 
     16 │     SpecialProperty
   
-  i The name could be renamed to `property`.
-  
 
 ```
 
@@ -168,25 +154,21 @@ invalidClassProperty.js:16:5 lint/style/useNamingConvention ━━━━━━
     17 │ 
     18 │     #SpecialProperty
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
-invalidClassProperty.js:18:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassProperty.js:18:6 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class property name should be in camelCase.
   
     16 │     SpecialProperty
     17 │ 
   > 18 │     #SpecialProperty
-       │     ^^^^^^^^^^^^^^^^
+       │      ^^^^^^^^^^^^^^^
     19 │ 
     20 │     special_property
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -202,25 +184,21 @@ invalidClassProperty.js:20:5 lint/style/useNamingConvention ━━━━━━
     21 │ 
     22 │     #special_property
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
-invalidClassProperty.js:22:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassProperty.js:22:6 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class property name should be in camelCase.
   
     20 │     special_property
     21 │ 
   > 22 │     #special_property
-       │     ^^^^^^^^^^^^^^^^^
+       │      ^^^^^^^^^^^^^^^^
     23 │ 
     24 │     Unknown_Style
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -236,25 +214,21 @@ invalidClassProperty.js:24:5 lint/style/useNamingConvention ━━━━━━
     25 │ 
     26 │     #Unknown_Style
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
 ```
-invalidClassProperty.js:26:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassProperty.js:26:6 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class property name should be in camelCase.
   
     24 │     Unknown_Style
     25 │ 
   > 26 │     #Unknown_Style
-       │     ^^^^^^^^^^^^^^
+       │      ^^^^^^^^^^^^^
     27 │ 
     28 │     Unknown_Init_Style = 0
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
@@ -270,25 +244,19 @@ invalidClassProperty.js:28:5 lint/style/useNamingConvention ━━━━━━
     29 │ 
     30 │     #Unknown_Init_Style = 0
   
-  i The name could be renamed to `unknownInitStyle`.
-  
 
 ```
 
 ```
-invalidClassProperty.js:30:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassProperty.js:30:6 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class property name should be in camelCase.
   
     28 │     Unknown_Init_Style = 0
     29 │ 
   > 30 │     #Unknown_Init_Style = 0
-       │     ^^^^^^^^^^^^^^^^^^^
+       │      ^^^^^^^^^^^^^^^^^^
     31 │ }
   
-  i The name could be renamed to `unknownInitStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassSetter.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassSetter.js.snap
index 446aa395a5ee..53daffaa799d 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassSetter.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassSetter.js.snap
@@ -39,8 +39,6 @@ invalidClassSetter.js:2:9 lint/style/useNamingConvention ━━━━━━━
     3 │ 
     4 │     set PROPERTY(x) {}
   
-  i The name could be renamed to `x`.
-  
 
 ```
 
@@ -56,8 +54,6 @@ invalidClassSetter.js:4:9 lint/style/useNamingConvention ━━━━━━━
     5 │ 
     6 │     set SpecialProperty(x) {}
   
-  i The name could be renamed to `property`.
-  
 
 ```
 
@@ -73,8 +69,6 @@ invalidClassSetter.js:6:9 lint/style/useNamingConvention ━━━━━━━
     7 │ 
     8 │     set special_property(x) {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -90,8 +84,6 @@ invalidClassSetter.js:8:9 lint/style/useNamingConvention ━━━━━━━
      9 │ 
     10 │     set Unknown_Style(x) {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -107,93 +99,79 @@ invalidClassSetter.js:10:9 lint/style/useNamingConvention ━━━━━━━
     11 │ 
     12 │     set #X(x) {}
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
 ```
-invalidClassSetter.js:12:9 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassSetter.js:12:10 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class setter name should be in camelCase.
   
     10 │     set Unknown_Style(x) {}
     11 │ 
   > 12 │     set #X(x) {}
-       │         ^^
+       │          ^
     13 │ 
     14 │     set #PROPERTY(x) {}
   
-  i The name could be renamed to `x`.
-  
 
 ```
 
 ```
-invalidClassSetter.js:14:9 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassSetter.js:14:10 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class setter name should be in camelCase.
   
     12 │     set #X(x) {}
     13 │ 
   > 14 │     set #PROPERTY(x) {}
-       │         ^^^^^^^^^
+       │          ^^^^^^^^
     15 │ 
     16 │     set #SpecialProperty(x) {}
   
-  i The name could be renamed to `property`.
-  
 
 ```
 
 ```
-invalidClassSetter.js:16:9 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassSetter.js:16:10 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class setter name should be in camelCase.
   
     14 │     set #PROPERTY(x) {}
     15 │ 
   > 16 │     set #SpecialProperty(x) {}
-       │         ^^^^^^^^^^^^^^^^
+       │          ^^^^^^^^^^^^^^^
     17 │ 
     18 │     set #special_property(x) {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
-invalidClassSetter.js:18:9 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassSetter.js:18:10 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class setter name should be in camelCase.
   
     16 │     set #SpecialProperty(x) {}
     17 │ 
   > 18 │     set #special_property(x) {}
-       │         ^^^^^^^^^^^^^^^^^
+       │          ^^^^^^^^^^^^^^^^
     19 │ 
     20 │     set #Unknown_Style(x) {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
-invalidClassSetter.js:20:9 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassSetter.js:20:10 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
   ! This class setter name should be in camelCase.
   
     18 │     set #special_property(x) {}
     19 │ 
   > 20 │     set #Unknown_Style(x) {}
-       │         ^^^^^^^^^^^^^^
+       │          ^^^^^^^^^^^^^
     21 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassStaticGetter.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassStaticGetter.js.snap
index 682e1b230ae7..7c9c4932fbed 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassStaticGetter.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassStaticGetter.js.snap
@@ -25,7 +25,7 @@ export default class {
 ```
 invalidClassStaticGetter.js:2:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static getter name should be in camelCase or CONSTANT_CASE.
+  ! This static class getter name should be in camelCase or CONSTANT_CASE.
   
     1 │ export default class {
   > 2 │     static get SpecialProperty() {}
@@ -33,15 +33,13 @@ invalidClassStaticGetter.js:2:16 lint/style/useNamingConvention ━━━━━
     3 │ 
     4 │     static get special_property() {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
 invalidClassStaticGetter.js:4:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static getter name should be in camelCase or CONSTANT_CASE.
+  ! This static class getter name should be in camelCase or CONSTANT_CASE.
   
     2 │     static get SpecialProperty() {}
     3 │ 
@@ -50,15 +48,13 @@ invalidClassStaticGetter.js:4:16 lint/style/useNamingConvention ━━━━━
     5 │ 
     6 │     static get Unknown_Style() {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
 invalidClassStaticGetter.js:6:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static getter name should be in camelCase or CONSTANT_CASE.
+  ! This static class getter name should be in camelCase or CONSTANT_CASE.
   
     4 │     static get special_property() {}
     5 │ 
@@ -67,59 +63,49 @@ invalidClassStaticGetter.js:6:16 lint/style/useNamingConvention ━━━━━
     7 │ 
     8 │     static get #X() {}
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
 ```
-invalidClassStaticGetter.js:10:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticGetter.js:10:17 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static getter name should be in camelCase or CONSTANT_CASE.
+  ! This static class getter name should be in camelCase or CONSTANT_CASE.
   
      8 │     static get #X() {}
      9 │ 
   > 10 │     static get #SpecialProperty() {}
-       │                ^^^^^^^^^^^^^^^^
+       │                 ^^^^^^^^^^^^^^^
     11 │ 
     12 │     static get #special_property() {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
-invalidClassStaticGetter.js:12:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticGetter.js:12:17 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static getter name should be in camelCase or CONSTANT_CASE.
+  ! This static class getter name should be in camelCase or CONSTANT_CASE.
   
     10 │     static get #SpecialProperty() {}
     11 │ 
   > 12 │     static get #special_property() {}
-       │                ^^^^^^^^^^^^^^^^^
+       │                 ^^^^^^^^^^^^^^^^
     13 │ 
     14 │     static get #Unknown_Style() {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
-invalidClassStaticGetter.js:14:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticGetter.js:14:17 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static getter name should be in camelCase or CONSTANT_CASE.
+  ! This static class getter name should be in camelCase or CONSTANT_CASE.
   
     12 │     static get #special_property() {}
     13 │ 
   > 14 │     static get #Unknown_Style() {}
-       │                ^^^^^^^^^^^^^^
+       │                 ^^^^^^^^^^^^^
     15 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassStaticMethod.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassStaticMethod.js.snap
index 6faf2c462edc..7235210bbc44 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassStaticMethod.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassStaticMethod.js.snap
@@ -29,7 +29,7 @@ export default class {
 ```
 invalidClassStaticMethod.js:2:12 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static method name should be in camelCase.
+  ! This class method name should be in camelCase.
   
     1 │ export default class {
   > 2 │     static METHOD() {}
@@ -37,15 +37,13 @@ invalidClassStaticMethod.js:2:12 lint/style/useNamingConvention ━━━━━
     3 │ 
     4 │     static AMethod() {}
   
-  i The name could be renamed to `method`.
-  
 
 ```
 
 ```
 invalidClassStaticMethod.js:4:12 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static method name should be in camelCase.
+  ! Two consecutive uppercase characters are not allowed in PascalCase because strictCase is set to `true`.
   
     2 │     static METHOD() {}
     3 │ 
@@ -54,7 +52,8 @@ invalidClassStaticMethod.js:4:12 lint/style/useNamingConvention ━━━━━
     5 │ 
     6 │     static method_1() {}
   
-  i The name could be renamed to `aMethod`.
+  i If you want to use consecutive uppercase characters in PascalCase, then set the strictCase option to `false`.
+    See the rule options for more details.
   
 
 ```
@@ -62,7 +61,7 @@ invalidClassStaticMethod.js:4:12 lint/style/useNamingConvention ━━━━━
 ```
 invalidClassStaticMethod.js:6:12 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static method name should be in camelCase.
+  ! This class method name should be in camelCase.
   
     4 │     static AMethod() {}
     5 │ 
@@ -71,15 +70,13 @@ invalidClassStaticMethod.js:6:12 lint/style/useNamingConvention ━━━━━
     7 │ 
     8 │     static Unknown_Style() {}
   
-  i The name could be renamed to `method1`.
-  
 
 ```
 
 ```
 invalidClassStaticMethod.js:8:12 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static method name should be in camelCase.
+  ! This class method name should be in camelCase.
   
      6 │     static method_1() {}
      7 │ 
@@ -88,93 +85,82 @@ invalidClassStaticMethod.js:8:12 lint/style/useNamingConvention ━━━━━
      9 │ 
     10 │     static #M() {}
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
 ```
-invalidClassStaticMethod.js:10:12 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticMethod.js:10:13 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static method name should be in camelCase.
+  ! This class method name should be in camelCase.
   
      8 │     static Unknown_Style() {}
      9 │ 
   > 10 │     static #M() {}
-       │            ^^
+       │             ^
     11 │ 
     12 │     static #METHOD() {}
   
-  i The name could be renamed to `m`.
-  
 
 ```
 
 ```
-invalidClassStaticMethod.js:12:12 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticMethod.js:12:13 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static method name should be in camelCase.
+  ! This class method name should be in camelCase.
   
     10 │     static #M() {}
     11 │ 
   > 12 │     static #METHOD() {}
-       │            ^^^^^^^
+       │             ^^^^^^
     13 │ 
     14 │     static #AMethod() {}
   
-  i The name could be renamed to `method`.
-  
 
 ```
 
 ```
-invalidClassStaticMethod.js:14:12 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticMethod.js:14:13 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static method name should be in camelCase.
+  ! Two consecutive uppercase characters are not allowed in PascalCase because strictCase is set to `true`.
   
     12 │     static #METHOD() {}
     13 │ 
   > 14 │     static #AMethod() {}
-       │            ^^^^^^^^
+       │             ^^^^^^^
     15 │ 
     16 │     static #method_1() {}
   
-  i The name could be renamed to `aMethod`.
+  i If you want to use consecutive uppercase characters in PascalCase, then set the strictCase option to `false`.
+    See the rule options for more details.
   
 
 ```
 
 ```
-invalidClassStaticMethod.js:16:12 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticMethod.js:16:13 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static method name should be in camelCase.
+  ! This class method name should be in camelCase.
   
     14 │     static #AMethod() {}
     15 │ 
   > 16 │     static #method_1() {}
-       │            ^^^^^^^^^
+       │             ^^^^^^^^
     17 │ 
     18 │     static #Unknown_Style() {}
   
-  i The name could be renamed to `method1`.
-  
 
 ```
 
 ```
-invalidClassStaticMethod.js:18:12 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticMethod.js:18:13 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static method name should be in camelCase.
+  ! This class method name should be in camelCase.
   
     16 │     static #method_1() {}
     17 │ 
   > 18 │     static #Unknown_Style() {}
-       │            ^^^^^^^^^^^^^^
+       │             ^^^^^^^^^^^^^
     19 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassStaticSetter.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassStaticSetter.js.snap
index d234edf6ddae..212af41b60bf 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassStaticSetter.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidClassStaticSetter.js.snap
@@ -31,7 +31,7 @@ export default class {
 ```
 invalidClassStaticSetter.js:2:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static setter name should be in camelCase.
+  ! This class setter name should be in camelCase.
   
     1 │ export default class {
   > 2 │     static set X(x) {}
@@ -39,15 +39,13 @@ invalidClassStaticSetter.js:2:16 lint/style/useNamingConvention ━━━━━
     3 │ 
     4 │     static set PROPERTY(x) {}
   
-  i The name could be renamed to `x`.
-  
 
 ```
 
 ```
 invalidClassStaticSetter.js:4:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static setter name should be in camelCase.
+  ! This class setter name should be in camelCase.
   
     2 │     static set X(x) {}
     3 │ 
@@ -56,15 +54,13 @@ invalidClassStaticSetter.js:4:16 lint/style/useNamingConvention ━━━━━
     5 │ 
     6 │     static set SpecialProperty(x) {}
   
-  i The name could be renamed to `property`.
-  
 
 ```
 
 ```
 invalidClassStaticSetter.js:6:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static setter name should be in camelCase.
+  ! This class setter name should be in camelCase.
   
     4 │     static set PROPERTY(x) {}
     5 │ 
@@ -73,15 +69,13 @@ invalidClassStaticSetter.js:6:16 lint/style/useNamingConvention ━━━━━
     7 │ 
     8 │     static set special_property(x) {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
 invalidClassStaticSetter.js:8:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static setter name should be in camelCase.
+  ! This class setter name should be in camelCase.
   
      6 │     static set SpecialProperty(x) {}
      7 │ 
@@ -90,15 +84,13 @@ invalidClassStaticSetter.js:8:16 lint/style/useNamingConvention ━━━━━
      9 │ 
     10 │     static set Unknown_Style(x) {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
 invalidClassStaticSetter.js:10:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static setter name should be in camelCase.
+  ! This class setter name should be in camelCase.
   
      8 │     static set special_property(x) {}
      9 │ 
@@ -107,93 +99,79 @@ invalidClassStaticSetter.js:10:16 lint/style/useNamingConvention ━━━━━
     11 │ 
     12 │     static set #X(x) {}
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
 ```
-invalidClassStaticSetter.js:12:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticSetter.js:12:17 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static setter name should be in camelCase.
+  ! This class setter name should be in camelCase.
   
     10 │     static set Unknown_Style(x) {}
     11 │ 
   > 12 │     static set #X(x) {}
-       │                ^^
+       │                 ^
     13 │ 
     14 │     static set #PROPERTY(x) {}
   
-  i The name could be renamed to `x`.
-  
 
 ```
 
 ```
-invalidClassStaticSetter.js:14:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticSetter.js:14:17 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static setter name should be in camelCase.
+  ! This class setter name should be in camelCase.
   
     12 │     static set #X(x) {}
     13 │ 
   > 14 │     static set #PROPERTY(x) {}
-       │                ^^^^^^^^^
+       │                 ^^^^^^^^
     15 │ 
     16 │     static set #SpecialProperty(x) {}
   
-  i The name could be renamed to `property`.
-  
 
 ```
 
 ```
-invalidClassStaticSetter.js:16:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticSetter.js:16:17 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static setter name should be in camelCase.
+  ! This class setter name should be in camelCase.
   
     14 │     static set #PROPERTY(x) {}
     15 │ 
   > 16 │     static set #SpecialProperty(x) {}
-       │                ^^^^^^^^^^^^^^^^
+       │                 ^^^^^^^^^^^^^^^
     17 │ 
     18 │     static set #special_property(x) {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
-invalidClassStaticSetter.js:18:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticSetter.js:18:17 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static setter name should be in camelCase.
+  ! This class setter name should be in camelCase.
   
     16 │     static set #SpecialProperty(x) {}
     17 │ 
   > 18 │     static set #special_property(x) {}
-       │                ^^^^^^^^^^^^^^^^^
+       │                 ^^^^^^^^^^^^^^^^
     19 │ 
     20 │     static set #Unknown_Style(x) {}
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
 ```
-invalidClassStaticSetter.js:20:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidClassStaticSetter.js:20:17 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This static setter name should be in camelCase.
+  ! This class setter name should be in camelCase.
   
     18 │     static set #special_property(x) {}
     19 │ 
   > 20 │     static set #Unknown_Style(x) {}
-       │                ^^^^^^^^^^^^^^
+       │                 ^^^^^^^^^^^^^
     21 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyle.options.json b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyle.options.json
new file mode 100644
index 000000000000..564576f2fe29
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyle.options.json
@@ -0,0 +1,21 @@
+{
+	"linter": {
+		"rules": {
+			"style": {
+				"useNamingConvention": {
+					"level": "error",
+					"options": {
+						"custom": [
+							{
+								"selector": {
+									"kind": "interface"
+								},
+								"match": "I(.+)|(.*)Error"
+							}
+						]
+					}
+				}
+			}
+		}
+	}
+}
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyle.ts b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyle.ts
new file mode 100644
index 000000000000..827d0c2e0887
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyle.ts
@@ -0,0 +1,8 @@
+// Valid
+//interface IArguments {}
+//interface Error {}
+//interface CustomError {}
+
+// Invalid
+interface Invalid {}
+//interface Other {}
\ No newline at end of file
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyle.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyle.ts.snap
new file mode 100644
index 000000000000..f98ad43515aa
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyle.ts.snap
@@ -0,0 +1,37 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: invalidCustomStyle.ts
+---
+# Input
+```ts
+// Valid
+//interface IArguments {}
+//interface Error {}
+//interface CustomError {}
+
+// Invalid
+interface Invalid {}
+//interface Other {}
+```
+
+# Diagnostics
+```
+invalidCustomStyle.ts:7:12 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! This interface name part should be in PascalCase.
+  
+    6 │ // Invalid
+  > 7 │ interface Invalid {}
+      │            ^^^^^^
+    8 │ //interface Other {}
+  
+  i Safe fix: Rename this symbol in PascalCase.
+  
+    5 5 │   
+    6 6 │   // Invalid
+    7   │ - interface·Invalid·{}
+      7 │ + interface·INvalid·{}
+    8 8 │   //interface Other {}
+  
+
+```
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleExceptions.options.json b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleExceptions.options.json
new file mode 100644
index 000000000000..6a5b7b3f2914
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleExceptions.options.json
@@ -0,0 +1,19 @@
+{
+	"$schema": "../../../../../../packages/@biomejs/biome/configuration_schema.json",
+	"linter": {
+		"rules": {
+			"style": {
+				"useNamingConvention": {
+					"level": "error",
+					"options": {
+                        "custom": [
+							{
+								"match": "aSepcial_CASE|(.*)"
+							}
+                        ]
+					}
+				}
+			}
+		}
+	}
+}
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleExceptions.ts b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleExceptions.ts
new file mode 100644
index 000000000000..ff60210dedaa
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleExceptions.ts
@@ -0,0 +1,2 @@
+const aSepcial_CASE = 0; // valid
+const aSepcial_CASE_2 = 0; // invalid
\ No newline at end of file
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleExceptions.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleExceptions.ts.snap
new file mode 100644
index 000000000000..9ce750432319
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleExceptions.ts.snap
@@ -0,0 +1,28 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: invalidCustomStyleExceptions.ts
+---
+# Input
+```ts
+const aSepcial_CASE = 0; // valid
+const aSepcial_CASE_2 = 0; // invalid
+```
+
+# Diagnostics
+```
+invalidCustomStyleExceptions.ts:2:7 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! This global const name should be in camelCase or PascalCase or CONSTANT_CASE.
+  
+    1 │ const aSepcial_CASE = 0; // valid
+  > 2 │ const aSepcial_CASE_2 = 0; // invalid
+      │       ^^^^^^^^^^^^^^^
+  
+  i Safe fix: Rename this symbol in camelCase.
+  
+    1 1 │   const aSepcial_CASE = 0; // valid
+    2   │ - const·aSepcial_CASE_2·=·0;·//·invalid
+      2 │ + const·aSepcialCase2·=·0;·//·invalid
+  
+
+```
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleUnderscorePrivate.options.json b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleUnderscorePrivate.options.json
new file mode 100644
index 000000000000..00fe89de4ffc
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleUnderscorePrivate.options.json
@@ -0,0 +1,23 @@
+{
+	"$schema": "../../../../../../packages/@biomejs/biome/configuration_schema.json",
+	"linter": {
+		"rules": {
+			"style": {
+				"useNamingConvention": {
+					"level": "error",
+					"options": {
+                        "custom": [
+                            {
+                                "selector": {
+									"kind": "memberLike",
+                                	"modifiers": ["private"]
+								},
+								"match": "^_(.*)$"
+                            }
+                        ]
+					}
+				}
+			}
+		}
+	}
+}
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleUnderscorePrivate.ts b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleUnderscorePrivate.ts
new file mode 100644
index 000000000000..413d31683f74
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleUnderscorePrivate.ts
@@ -0,0 +1,3 @@
+class X {
+    private property: number
+}
\ No newline at end of file
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleUnderscorePrivate.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleUnderscorePrivate.ts.snap
new file mode 100644
index 000000000000..2e881f40961b
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidCustomStyleUnderscorePrivate.ts.snap
@@ -0,0 +1,24 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: invalidCustomStyleUnderscorePrivate.ts
+---
+# Input
+```ts
+class X {
+    private property: number
+}
+```
+
+# Diagnostics
+```
+invalidCustomStyleUnderscorePrivate.ts:2:13 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! This private member name part should match the following regex /^_(.*)$/.
+  
+    1 │ class X {
+  > 2 │     private property: number
+      │             ^^^^^^^^
+    3 │ }
+  
+
+```
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidEnum.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidEnum.ts.snap
index a998c19820aa..5053cec2a9a4 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidEnum.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidEnum.ts.snap
@@ -22,8 +22,6 @@ invalidEnum.ts:1:6 lint/style/useNamingConvention  FIXABLE  ━━━━━━
     2 │ 
     3 │ enum special_status {}
   
-  i The name could be renamed to `SpecialStatus`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
     1   │ - enum·specialStatus·{}
@@ -46,8 +44,6 @@ invalidEnum.ts:3:6 lint/style/useNamingConvention  FIXABLE  ━━━━━━
     4 │ 
     5 │ enum SPECIAL_STATUS {}
   
-  i The name could be renamed to `SpecialStatus`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
     1 1 │   enum specialStatus {}
@@ -70,8 +66,6 @@ invalidEnum.ts:5:6 lint/style/useNamingConvention  FIXABLE  ━━━━━━
   > 5 │ enum SPECIAL_STATUS {}
       │      ^^^^^^^^^^^^^^
   
-  i The name could be renamed to `SpecialStatus`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
     3 3 │   enum special_status {}
@@ -81,5 +75,3 @@ invalidEnum.ts:5:6 lint/style/useNamingConvention  FIXABLE  ━━━━━━
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidEnumMember.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidEnumMember.ts.snap
index 7d00497b7406..47a192adbb7b 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidEnumMember.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidEnumMember.ts.snap
@@ -27,8 +27,6 @@ invalidEnumMember.ts:2:5 lint/style/useNamingConvention ━━━━━━━━
     3 │     CLOSE,
     4 │ }
   
-  i The name could be renamed to `Open`.
-  
 
 ```
 
@@ -44,8 +42,6 @@ invalidEnumMember.ts:3:5 lint/style/useNamingConvention ━━━━━━━━
     4 │ }
     5 │ 
   
-  i The name could be renamed to `Close`.
-  
 
 ```
 
@@ -60,8 +56,6 @@ invalidEnumMember.ts:7:5 lint/style/useNamingConvention ━━━━━━━━
     8 │     left,
     9 │ }
   
-  i The name could be renamed to `Right`.
-  
 
 ```
 
@@ -76,9 +70,5 @@ invalidEnumMember.ts:8:5 lint/style/useNamingConvention ━━━━━━━━
       │     ^^^^
     9 │ }
   
-  i The name could be renamed to `Left`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidExportAlias.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidExportAlias.js.snap
index c1e938dec7d8..1c479f6094e5 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidExportAlias.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidExportAlias.js.snap
@@ -17,14 +17,15 @@ export { Y as snake_case  } from ""
 ```
 invalidExportAlias.js:1:15 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This export alias name should be in camelCase or PascalCase or CONSTANT_CASE.
+  ! Two consecutive uppercase characters are not allowed in PascalCase because strictCase is set to `true`.
   
   > 1 │ export { X as XxXX }
       │               ^^^^
     2 │ 
     3 │ export { Y as snake_case  }
   
-  i The name could be renamed to `xxXx`.
+  i If you want to use consecutive uppercase characters in PascalCase, then set the strictCase option to `false`.
+    See the rule options for more details.
   
 
 ```
@@ -41,15 +42,13 @@ invalidExportAlias.js:3:15 lint/style/useNamingConvention ━━━━━━━
     4 │ 
     5 │ export { X as XxXX } from ""
   
-  i The name could be renamed to `snakeCase`.
-  
 
 ```
 
 ```
 invalidExportAlias.js:5:15 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This export alias name should be in camelCase or PascalCase or CONSTANT_CASE.
+  ! Two consecutive uppercase characters are not allowed in PascalCase because strictCase is set to `true`.
   
     3 │ export { Y as snake_case  }
     4 │ 
@@ -58,7 +57,8 @@ invalidExportAlias.js:5:15 lint/style/useNamingConvention ━━━━━━━
     6 │ 
     7 │ export { Y as snake_case  } from ""
   
-  i The name could be renamed to `xxXx`.
+  i If you want to use consecutive uppercase characters in PascalCase, then set the strictCase option to `false`.
+    See the rule options for more details.
   
 
 ```
@@ -73,9 +73,5 @@ invalidExportAlias.js:7:15 lint/style/useNamingConvention ━━━━━━━
   > 7 │ export { Y as snake_case  } from ""
       │               ^^^^^^^^^^
   
-  i The name could be renamed to `snakeCase`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidExportNamespace.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidExportNamespace.js.snap
index 0ad1e97b7326..1964b4abd5ea 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidExportNamespace.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidExportNamespace.js.snap
@@ -29,8 +29,6 @@ invalidExportNamespace.js:5:13 lint/style/useNamingConvention ━━━━━━
     6 │ 
     7 │ export * as snake_case from ""
   
-  i The name could be renamed to `constantCase`.
-  
 
 ```
 
@@ -46,8 +44,6 @@ invalidExportNamespace.js:7:13 lint/style/useNamingConvention ━━━━━━
     8 │ 
     9 │ export * as Unknown_Style from ""
   
-  i The name could be renamed to `snakeCase`.
-  
 
 ```
 
@@ -62,9 +58,5 @@ invalidExportNamespace.js:9:13 lint/style/useNamingConvention ━━━━━━
        │             ^^^^^^^^^^^^^
     10 │ 
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidFunction.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidFunction.js.snap
index 96fc6a853bf9..8f71d36d08c6 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidFunction.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidFunction.js.snap
@@ -24,8 +24,6 @@ invalidFunction.js:1:10 lint/style/useNamingConvention  FIXABLE  ━━━━━
     2 │ 
     3 │ function special_function() {}
   
-  i The name could be renamed to `person`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     1   │ - function·PERSON()·{}
@@ -48,8 +46,6 @@ invalidFunction.js:3:10 lint/style/useNamingConvention  FIXABLE  ━━━━━
     4 │ 
     5 │ function Unknown_Style() {}
   
-  i The name could be renamed to `specialFunction`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     1 1 │   function PERSON() {}
@@ -74,8 +70,6 @@ invalidFunction.js:5:10 lint/style/useNamingConvention  FIXABLE  ━━━━━
     6 │ 
     7 │ const g = function SPECIAL_FUNCTION() {}
   
-  i The name could be renamed to `unknownStyle`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     3 3 │   function special_function() {}
@@ -98,8 +92,6 @@ invalidFunction.js:7:20 lint/style/useNamingConvention  FIXABLE  ━━━━━
   > 7 │ const g = function SPECIAL_FUNCTION() {}
       │                    ^^^^^^^^^^^^^^^^
   
-  i The name could be renamed to `specialFunction`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     5 5 │   function Unknown_Style() {}
@@ -109,5 +101,3 @@ invalidFunction.js:7:20 lint/style/useNamingConvention  FIXABLE  ━━━━━
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidFunctionParameter.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidFunctionParameter.js.snap
index 88f0a4f20b15..7d6ff9323bf8 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidFunctionParameter.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidFunctionParameter.js.snap
@@ -9,14 +9,12 @@ function f(_snake_case, CONSTANT_CASE) {}
 
 # Diagnostics
 ```
-invalidFunctionParameter.js:1:12 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidFunctionParameter.js:1:13 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This function parameter name trimmed as `snake_case` should be in camelCase or PascalCase.
+  ! This function parameter name part should be in camelCase or PascalCase.
   
   > 1 │ function f(_snake_case, CONSTANT_CASE) {}
-      │            ^^^^^^^^^^^
-  
-  i The name could be renamed to `_snakeCase`.
+      │             ^^^^^^^^^^
   
   i Safe fix: Rename this symbol in camelCase.
   
@@ -34,8 +32,6 @@ invalidFunctionParameter.js:1:25 lint/style/useNamingConvention  FIXABLE  ━━
   > 1 │ function f(_snake_case, CONSTANT_CASE) {}
       │                         ^^^^^^^^^^^^^
   
-  i The name could be renamed to `constantCase`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
   - function·f(_snake_case,·CONSTANT_CASE)·{}
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidImportAlias.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidImportAlias.js.snap
index e245902428d7..4b3288650b46 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidImportAlias.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidImportAlias.js.snap
@@ -25,14 +25,15 @@ import snake_case from ""
 ```
 invalidImportAlias.js:1:15 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This import alias name should be in camelCase or PascalCase or CONSTANT_CASE.
+  ! Two consecutive uppercase characters are not allowed in PascalCase because strictCase is set to `true`.
   
   > 1 │ import { X as XxXX } from ""
       │               ^^^^
     2 │ 
     3 │ import { Y as snake_case  } from ""
   
-  i The name could be renamed to `xxXx`.
+  i If you want to use consecutive uppercase characters in PascalCase, then set the strictCase option to `false`.
+    See the rule options for more details.
   
   i Safe fix: Rename this symbol in camelCase.
   
@@ -56,8 +57,6 @@ invalidImportAlias.js:3:15 lint/style/useNamingConvention  FIXABLE  ━━━━
     4 │ 
     5 │ import { X as XxXX } from ""
   
-  i The name could be renamed to `snakeCase`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
      1  1 │   import { X as XxXX } from ""
@@ -73,7 +72,7 @@ invalidImportAlias.js:3:15 lint/style/useNamingConvention  FIXABLE  ━━━━
 ```
 invalidImportAlias.js:5:15 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This import alias name should be in camelCase or PascalCase or CONSTANT_CASE.
+  ! Two consecutive uppercase characters are not allowed in PascalCase because strictCase is set to `true`.
   
     3 │ import { Y as snake_case  } from ""
     4 │ 
@@ -82,7 +81,8 @@ invalidImportAlias.js:5:15 lint/style/useNamingConvention  FIXABLE  ━━━━
     6 │ 
     7 │ import { Y as snake_case  } from ""
   
-  i The name could be renamed to `xxXx`.
+  i If you want to use consecutive uppercase characters in PascalCase, then set the strictCase option to `false`.
+    See the rule options for more details.
   
   i Safe fix: Rename this symbol in camelCase.
   
@@ -108,8 +108,6 @@ invalidImportAlias.js:7:15 lint/style/useNamingConvention  FIXABLE  ━━━━
     8 │ 
     9 │ import XxXX from ""
   
-  i The name could be renamed to `snakeCase`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
      5  5 │   import { X as XxXX } from ""
@@ -125,7 +123,7 @@ invalidImportAlias.js:7:15 lint/style/useNamingConvention  FIXABLE  ━━━━
 ```
 invalidImportAlias.js:9:8 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This import alias name should be in camelCase or PascalCase or CONSTANT_CASE.
+  ! Two consecutive uppercase characters are not allowed in PascalCase because strictCase is set to `true`.
   
      7 │ import { Y as snake_case  } from ""
      8 │ 
@@ -134,7 +132,8 @@ invalidImportAlias.js:9:8 lint/style/useNamingConvention  FIXABLE  ━━━━
     10 │ 
     11 │ import snake_case from ""
   
-  i The name could be renamed to `xxXx`.
+  i If you want to use consecutive uppercase characters in PascalCase, then set the strictCase option to `false`.
+    See the rule options for more details.
   
   i Safe fix: Rename this symbol in camelCase.
   
@@ -160,8 +159,6 @@ invalidImportAlias.js:11:8 lint/style/useNamingConvention  FIXABLE  ━━━━
     12 │ 
     13 │ import XxXX from ""
   
-  i The name could be renamed to `snakeCase`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
      9  9 │   import XxXX from ""
@@ -177,7 +174,7 @@ invalidImportAlias.js:11:8 lint/style/useNamingConvention  FIXABLE  ━━━━
 ```
 invalidImportAlias.js:13:8 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This import alias name should be in camelCase or PascalCase or CONSTANT_CASE.
+  ! Two consecutive uppercase characters are not allowed in PascalCase because strictCase is set to `true`.
   
     11 │ import snake_case from ""
     12 │ 
@@ -186,7 +183,8 @@ invalidImportAlias.js:13:8 lint/style/useNamingConvention  FIXABLE  ━━━━
     14 │ 
     15 │ import snake_case from ""
   
-  i The name could be renamed to `xxXx`.
+  i If you want to use consecutive uppercase characters in PascalCase, then set the strictCase option to `false`.
+    See the rule options for more details.
   
   i Safe fix: Rename this symbol in camelCase.
   
@@ -210,8 +208,6 @@ invalidImportAlias.js:15:8 lint/style/useNamingConvention  FIXABLE  ━━━━
   > 15 │ import snake_case from ""
        │        ^^^^^^^^^^
   
-  i The name could be renamed to `snakeCase`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     13 13 │   import XxXX from ""
@@ -221,5 +217,3 @@ invalidImportAlias.js:15:8 lint/style/useNamingConvention  FIXABLE  ━━━━
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidImportNamespace.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidImportNamespace.js.snap
index b7e87a30d2c3..226a79c6f15c 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidImportNamespace.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidImportNamespace.js.snap
@@ -29,8 +29,6 @@ invalidImportNamespace.js:5:13 lint/style/useNamingConvention  FIXABLE  ━━
     6 │ 
     7 │ import * as snake_case from ""
   
-  i The name could be renamed to `constantCase`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
      3  3 │   import * as PascalCase from ""
@@ -55,8 +53,6 @@ invalidImportNamespace.js:7:13 lint/style/useNamingConvention  FIXABLE  ━━
     8 │ 
     9 │ import * as Unknown_Style from ""
   
-  i The name could be renamed to `snakeCase`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
      5  5 │   import * as CONSTANT_CASE from ""
@@ -80,8 +76,6 @@ invalidImportNamespace.js:9:13 lint/style/useNamingConvention  FIXABLE  ━━
        │             ^^^^^^^^^^^^^
     10 │ 
   
-  i The name could be renamed to `unknownStyle`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
      7  7 │   import * as snake_case from ""
@@ -92,5 +86,3 @@ invalidImportNamespace.js:9:13 lint/style/useNamingConvention  FIXABLE  ━━
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidIndexParameter.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidIndexParameter.ts.snap
index abdd5492039b..a24c9277437a 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidIndexParameter.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidIndexParameter.ts.snap
@@ -25,8 +25,6 @@ invalidIndexParameter.ts:2:6 lint/style/useNamingConvention  FIXABLE  ━━━
     3 │ 
     4 │     [CONSTANT_CASE: number]: unknown
   
-  i The name could be renamed to `pascalCase`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     1 1 │   export interface X {
@@ -50,8 +48,6 @@ invalidIndexParameter.ts:4:6 lint/style/useNamingConvention  FIXABLE  ━━━
     5 │ 
     6 │     [snake_case: symbol]: unknown
   
-  i The name could be renamed to `constantCase`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     2 2 │       [PascalCase: string]: unknown
@@ -75,8 +71,6 @@ invalidIndexParameter.ts:6:6 lint/style/useNamingConvention  FIXABLE  ━━━
       │      ^^^^^^^^^^
     7 │ }
   
-  i The name could be renamed to `snakeCase`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     4 4 │       [CONSTANT_CASE: number]: unknown
@@ -87,5 +81,3 @@ invalidIndexParameter.ts:6:6 lint/style/useNamingConvention  FIXABLE  ━━━
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidInterface.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidInterface.ts.snap
index 16d978bfd7ba..fa28ac83eb81 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidInterface.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidInterface.ts.snap
@@ -36,8 +36,6 @@ invalidInterface.ts:1:18 lint/style/useNamingConvention ━━━━━━━━
     2 │ 
     3 │ export interface CONSTANT_CASE {}
   
-  i The name could be renamed to `Xxx`.
-  
 
 ```
 
@@ -53,8 +51,6 @@ invalidInterface.ts:3:18 lint/style/useNamingConvention ━━━━━━━━
     4 │ 
     5 │ export interface camelCase {}
   
-  i The name could be renamed to `ConstantCase`.
-  
 
 ```
 
@@ -70,8 +66,6 @@ invalidInterface.ts:5:18 lint/style/useNamingConvention ━━━━━━━━
     6 │ 
     7 │ export interface snake_case {}
   
-  i The name could be renamed to `CamelCase`.
-  
 
 ```
 
@@ -87,8 +81,6 @@ invalidInterface.ts:7:18 lint/style/useNamingConvention ━━━━━━━━
     8 │ 
     9 │ export interface Unknown_Style {}
   
-  i The name could be renamed to `SnakeCase`.
-  
 
 ```
 
@@ -104,25 +96,21 @@ invalidInterface.ts:9:18 lint/style/useNamingConvention ━━━━━━━━
     10 │ 
     11 │ interface _XXX {}
   
-  i The name could be renamed to `UnknownStyle`.
-  
 
 ```
 
 ```
-invalidInterface.ts:11:11 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidInterface.ts:11:12 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This interface name trimmed as `XXX` should be in PascalCase.
+  ! This interface name part should be in PascalCase.
   
      9 │ export interface Unknown_Style {}
     10 │ 
   > 11 │ interface _XXX {}
-       │           ^^^^
+       │            ^^^
     12 │ 
     13 │ interface _CONSTANT_CASE {}
   
-  i The name could be renamed to `_Xxx`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
      9  9 │   export interface Unknown_Style {}
@@ -136,19 +124,17 @@ invalidInterface.ts:11:11 lint/style/useNamingConvention  FIXABLE  ━━━━
 ```
 
 ```
-invalidInterface.ts:13:11 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidInterface.ts:13:12 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This interface name trimmed as `CONSTANT_CASE` should be in PascalCase.
+  ! This interface name part should be in PascalCase.
   
     11 │ interface _XXX {}
     12 │ 
   > 13 │ interface _CONSTANT_CASE {}
-       │           ^^^^^^^^^^^^^^
+       │            ^^^^^^^^^^^^^
     14 │ 
     15 │ interface _camelCase {}
   
-  i The name could be renamed to `_ConstantCase`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
     11 11 │   interface _XXX {}
@@ -162,19 +148,17 @@ invalidInterface.ts:13:11 lint/style/useNamingConvention  FIXABLE  ━━━━
 ```
 
 ```
-invalidInterface.ts:15:11 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidInterface.ts:15:12 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This interface name trimmed as `camelCase` should be in PascalCase.
+  ! This interface name part should be in PascalCase.
   
     13 │ interface _CONSTANT_CASE {}
     14 │ 
   > 15 │ interface _camelCase {}
-       │           ^^^^^^^^^^
+       │            ^^^^^^^^^
     16 │ 
     17 │ interface _snake_case {}
   
-  i The name could be renamed to `_CamelCase`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
     13 13 │   interface _CONSTANT_CASE {}
@@ -188,19 +172,17 @@ invalidInterface.ts:15:11 lint/style/useNamingConvention  FIXABLE  ━━━━
 ```
 
 ```
-invalidInterface.ts:17:11 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidInterface.ts:17:12 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This interface name trimmed as `snake_case` should be in PascalCase.
+  ! This interface name part should be in PascalCase.
   
     15 │ interface _camelCase {}
     16 │ 
   > 17 │ interface _snake_case {}
-       │           ^^^^^^^^^^^
+       │            ^^^^^^^^^^
     18 │ 
     19 │ interface _Unknown_Style {}
   
-  i The name could be renamed to `_SnakeCase`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
     15 15 │   interface _camelCase {}
@@ -214,16 +196,14 @@ invalidInterface.ts:17:11 lint/style/useNamingConvention  FIXABLE  ━━━━
 ```
 
 ```
-invalidInterface.ts:19:11 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidInterface.ts:19:12 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This interface name trimmed as `Unknown_Style` should be in PascalCase.
+  ! This interface name part should be in PascalCase.
   
     17 │ interface _snake_case {}
     18 │ 
   > 19 │ interface _Unknown_Style {}
-       │           ^^^^^^^^^^^^^^
-  
-  i The name could be renamed to `_UnknownStyle`.
+       │            ^^^^^^^^^^^^^
   
   i Safe fix: Rename this symbol in PascalCase.
   
@@ -234,5 +214,3 @@ invalidInterface.ts:19:11 lint/style/useNamingConvention  FIXABLE  ━━━━
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidLocalVariable.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidLocalVariable.js.snap
index 324e9b75290d..edeaff4e631b 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidLocalVariable.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidLocalVariable.js.snap
@@ -26,7 +26,7 @@ export function f() {
 ```
 invalidLocalVariable.js:2:11 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This local const name should be in camelCase or PascalCase.
+  ! This const name should be in camelCase or PascalCase.
   
     1 │ export default function () {
   > 2 │     const CONSTANT_CASE_CONST = 0
@@ -34,8 +34,6 @@ invalidLocalVariable.js:2:11 lint/style/useNamingConvention  FIXABLE  ━━━
     3 │ 
     4 │     let CONSTANT_CASE_LET
   
-  i The name could be renamed to `constantCaseConst`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
      1  1 │   export default function () {
@@ -50,7 +48,7 @@ invalidLocalVariable.js:2:11 lint/style/useNamingConvention  FIXABLE  ━━━
 ```
 invalidLocalVariable.js:4:9 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This local let name should be in camelCase or PascalCase.
+  ! This let name should be in camelCase or PascalCase.
   
     2 │     const CONSTANT_CASE_CONST = 0
     3 │ 
@@ -59,8 +57,6 @@ invalidLocalVariable.js:4:9 lint/style/useNamingConvention  FIXABLE  ━━━
     5 │ 
     6 │     var CONSTANT_CASE_VAR
   
-  i The name could be renamed to `constantCaseLet`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
      2  2 │       const CONSTANT_CASE_CONST = 0
@@ -76,7 +72,7 @@ invalidLocalVariable.js:4:9 lint/style/useNamingConvention  FIXABLE  ━━━
 ```
 invalidLocalVariable.js:6:9 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This local var name should be in camelCase or PascalCase.
+  ! This var name should be in camelCase or PascalCase.
   
     4 │     let CONSTANT_CASE_LET
     5 │ 
@@ -85,8 +81,6 @@ invalidLocalVariable.js:6:9 lint/style/useNamingConvention  FIXABLE  ━━━
     7 │ 
     8 │     const { prop: Unknown_Style } = obj
   
-  i The name could be renamed to `constantCaseVar`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
      4  4 │       let CONSTANT_CASE_LET
@@ -102,7 +96,7 @@ invalidLocalVariable.js:6:9 lint/style/useNamingConvention  FIXABLE  ━━━
 ```
 invalidLocalVariable.js:8:19 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This local const name should be in camelCase or PascalCase.
+  ! This const name should be in camelCase or PascalCase.
   
      6 │     var CONSTANT_CASE_VAR
      7 │ 
@@ -111,8 +105,6 @@ invalidLocalVariable.js:8:19 lint/style/useNamingConvention  FIXABLE  ━━━
      9 │ }
     10 │ 
   
-  i The name could be renamed to `unknownStyle`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
      6  6 │       var CONSTANT_CASE_VAR
@@ -128,7 +120,7 @@ invalidLocalVariable.js:8:19 lint/style/useNamingConvention  FIXABLE  ━━━
 ```
 invalidLocalVariable.js:12:11 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This local const name should be in camelCase or PascalCase.
+  ! This const name should be in camelCase or PascalCase.
   
     11 │ export function f() {
   > 12 │     const a_var = 0;
@@ -136,8 +128,6 @@ invalidLocalVariable.js:12:11 lint/style/useNamingConvention  FIXABLE  ━━━
     13 │     console.log(a_var);
     14 │     return a_var;
   
-  i The name could be renamed to `aVar`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     10 10 │   
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidNamespace.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidNamespace.ts.snap
index 9d00eff0d9f9..2f07a5bfc9e0 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidNamespace.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidNamespace.ts.snap
@@ -32,8 +32,6 @@ invalidNamespace.ts:1:18 lint/style/useNamingConvention ━━━━━━━━
     2 │ 
     3 │ export namespace CONSTANT_CASE {}
   
-  i The name could be renamed to `xxx`.
-  
 
 ```
 
@@ -49,8 +47,6 @@ invalidNamespace.ts:3:18 lint/style/useNamingConvention ━━━━━━━━
     4 │ 
     5 │ export namespace snake_case {}
   
-  i The name could be renamed to `constantCase`.
-  
 
 ```
 
@@ -66,8 +62,6 @@ invalidNamespace.ts:5:18 lint/style/useNamingConvention ━━━━━━━━
     6 │ 
     7 │ export namespace Unknown_Style {}
   
-  i The name could be renamed to `snakeCase`.
-  
 
 ```
 
@@ -83,25 +77,21 @@ invalidNamespace.ts:7:18 lint/style/useNamingConvention ━━━━━━━━
     8 │ 
     9 │ namespace _XXX {}
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
 ```
-invalidNamespace.ts:9:11 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidNamespace.ts:9:12 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This namespace name trimmed as `XXX` should be in camelCase or PascalCase.
+  ! This namespace name part should be in camelCase or PascalCase.
   
      7 │ export namespace Unknown_Style {}
      8 │ 
    > 9 │ namespace _XXX {}
-       │           ^^^^
+       │            ^^^
     10 │ 
     11 │ namespace _CONSTANT_CASE {}
   
-  i The name could be renamed to `_xxx`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
      7  7 │   export namespace Unknown_Style {}
@@ -115,19 +105,17 @@ invalidNamespace.ts:9:11 lint/style/useNamingConvention  FIXABLE  ━━━━
 ```
 
 ```
-invalidNamespace.ts:11:11 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidNamespace.ts:11:12 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This namespace name trimmed as `CONSTANT_CASE` should be in camelCase or PascalCase.
+  ! This namespace name part should be in camelCase or PascalCase.
   
      9 │ namespace _XXX {}
     10 │ 
   > 11 │ namespace _CONSTANT_CASE {}
-       │           ^^^^^^^^^^^^^^
+       │            ^^^^^^^^^^^^^
     12 │ 
     13 │ namespace _snake_case {}
   
-  i The name could be renamed to `_constantCase`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
      9  9 │   namespace _XXX {}
@@ -141,19 +129,17 @@ invalidNamespace.ts:11:11 lint/style/useNamingConvention  FIXABLE  ━━━━
 ```
 
 ```
-invalidNamespace.ts:13:11 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidNamespace.ts:13:12 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This namespace name trimmed as `snake_case` should be in camelCase or PascalCase.
+  ! This namespace name part should be in camelCase or PascalCase.
   
     11 │ namespace _CONSTANT_CASE {}
     12 │ 
   > 13 │ namespace _snake_case {}
-       │           ^^^^^^^^^^^
+       │            ^^^^^^^^^^
     14 │ 
     15 │ namespace _Unknown_Style {}
   
-  i The name could be renamed to `_snakeCase`.
-  
   i Safe fix: Rename this symbol in camelCase.
   
     11 11 │   namespace _CONSTANT_CASE {}
@@ -167,16 +153,14 @@ invalidNamespace.ts:13:11 lint/style/useNamingConvention  FIXABLE  ━━━━
 ```
 
 ```
-invalidNamespace.ts:15:11 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidNamespace.ts:15:12 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This namespace name trimmed as `Unknown_Style` should be in camelCase or PascalCase.
+  ! This namespace name part should be in camelCase or PascalCase.
   
     13 │ namespace _snake_case {}
     14 │ 
   > 15 │ namespace _Unknown_Style {}
-       │           ^^^^^^^^^^^^^^
-  
-  i The name could be renamed to `_unknownStyle`.
+       │            ^^^^^^^^^^^^^
   
   i Safe fix: Rename this symbol in camelCase.
   
@@ -187,5 +171,3 @@ invalidNamespace.ts:15:11 lint/style/useNamingConvention  FIXABLE  ━━━━
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidNonAscii.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidNonAscii.js.snap
index 3b781a4631cb..1e17cf31b84a 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidNonAscii.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidNonAscii.js.snap
@@ -11,7 +11,7 @@ const café = 0;
 ```
 invalidNonAscii.js:1:7 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This top-level const name should be in ASCII because requireAscii` is set to `true`.
+  ! This declaration name should be in ASCII because requireAscii is set to `true`.
   
   > 1 │ const café = 0;
       │       ^^^^
@@ -21,5 +21,3 @@ invalidNonAscii.js:1:7 lint/style/useNamingConvention ━━━━━━━━
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectGetter.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectGetter.js.snap
index 7d98a24d4027..26a925453ba6 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectGetter.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectGetter.js.snap
@@ -25,8 +25,6 @@ invalidObjectGetter.js:2:9 lint/style/useNamingConvention ━━━━━━━
     3 │ 
     4 │     get special_property() {},
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -42,8 +40,6 @@ invalidObjectGetter.js:4:9 lint/style/useNamingConvention ━━━━━━━
     5 │ 
     6 │     get Unknown_Style() {},
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -58,9 +54,5 @@ invalidObjectGetter.js:6:9 lint/style/useNamingConvention ━━━━━━━
       │         ^^^^^^^^^^^^^
     7 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectMethod.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectMethod.js.snap
index 42f6905be432..ede59d92362c 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectMethod.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectMethod.js.snap
@@ -27,15 +27,13 @@ invalidObjectMethod.js:2:5 lint/style/useNamingConvention ━━━━━━━
     3 │ 
     4 │     AMethod() {},
   
-  i The name could be renamed to `method`.
-  
 
 ```
 
 ```
 invalidObjectMethod.js:4:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This object method name should be in camelCase.
+  ! Two consecutive uppercase characters are not allowed in PascalCase because strictCase is set to `true`.
   
     2 │     METHOD() {},
     3 │ 
@@ -44,7 +42,8 @@ invalidObjectMethod.js:4:5 lint/style/useNamingConvention ━━━━━━━
     5 │ 
     6 │     method_1() {},
   
-  i The name could be renamed to `aMethod`.
+  i If you want to use consecutive uppercase characters in PascalCase, then set the strictCase option to `false`.
+    See the rule options for more details.
   
 
 ```
@@ -61,8 +60,6 @@ invalidObjectMethod.js:6:5 lint/style/useNamingConvention ━━━━━━━
     7 │ 
     8 │     Unknown_Style() {},
   
-  i The name could be renamed to `method1`.
-  
 
 ```
 
@@ -77,9 +74,5 @@ invalidObjectMethod.js:8:5 lint/style/useNamingConvention ━━━━━━━
       │     ^^^^^^^^^^^^^
     9 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectProperty.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectProperty.js.snap
index 74c9104c4a2b..749852b5eb8a 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectProperty.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectProperty.js.snap
@@ -29,8 +29,6 @@ invalidObjectProperty.js:2:5 lint/style/useNamingConvention ━━━━━━
     3 │ 
     4 │     SpecialProperty: 0,
   
-  i The name could be renamed to `initialized`.
-  
 
 ```
 
@@ -46,8 +44,6 @@ invalidObjectProperty.js:4:5 lint/style/useNamingConvention ━━━━━━
     5 │ 
     6 │     special_property: 0,
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -63,8 +59,6 @@ invalidObjectProperty.js:6:5 lint/style/useNamingConvention ━━━━━━
     7 │ 
     8 │     Unknown_Style: 0,
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -80,8 +74,6 @@ invalidObjectProperty.js:8:5 lint/style/useNamingConvention ━━━━━━
      9 │ 
     10 │     Unknown_Init_Style: 0,
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
@@ -96,9 +88,5 @@ invalidObjectProperty.js:10:5 lint/style/useNamingConvention ━━━━━━
        │     ^^^^^^^^^^^^^^^^^^
     11 │ }
   
-  i The name could be renamed to `unknownInitStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectSetter.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectSetter.js.snap
index 2e0eaf1772f4..008cb84ddedb 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectSetter.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidObjectSetter.js.snap
@@ -29,8 +29,6 @@ invalidObjectSetter.js:2:9 lint/style/useNamingConvention ━━━━━━━
     3 │ 
     4 │     set PROPERTY(x) {},
   
-  i The name could be renamed to `x`.
-  
 
 ```
 
@@ -46,8 +44,6 @@ invalidObjectSetter.js:4:9 lint/style/useNamingConvention ━━━━━━━
     5 │ 
     6 │     set SpecialProperty(x) {},
   
-  i The name could be renamed to `property`.
-  
 
 ```
 
@@ -63,8 +59,6 @@ invalidObjectSetter.js:6:9 lint/style/useNamingConvention ━━━━━━━
     7 │ 
     8 │     set special_property(x) {},
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -80,8 +74,6 @@ invalidObjectSetter.js:8:9 lint/style/useNamingConvention ━━━━━━━
      9 │ 
     10 │     set Unknown_Style(x) {},
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -96,9 +88,5 @@ invalidObjectSetter.js:10:9 lint/style/useNamingConvention ━━━━━━━
        │         ^^^^^^^^^^^^^
     11 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterProperty.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterProperty.ts.snap
index 444b6173d751..9105c6c0ccd1 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterProperty.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterProperty.ts.snap
@@ -19,7 +19,7 @@ export default class {
 ```
 invalidParameterProperty.ts:3:18 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This parameter property name should be in camelCase.
+  ! This class property name should be in camelCase.
   
     1 │ export default class {
     2 │     constructor(
@@ -28,15 +28,13 @@ invalidParameterProperty.ts:3:18 lint/style/useNamingConvention ━━━━━
     4 │ 
     5 │         protected CONSTANT_CASE: unknown,
   
-  i The name could be renamed to `pascalCase`.
-  
 
 ```
 
 ```
 invalidParameterProperty.ts:5:19 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This parameter property name should be in camelCase.
+  ! This class property name should be in camelCase.
   
     3 │         readonly PascalCase: unknown,
     4 │ 
@@ -45,15 +43,13 @@ invalidParameterProperty.ts:5:19 lint/style/useNamingConvention ━━━━━
     6 │ 
     7 │         public Unknown_Style: unknown,
   
-  i The name could be renamed to `constantCase`.
-  
 
 ```
 
 ```
 invalidParameterProperty.ts:7:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This parameter property name should be in camelCase.
+  ! This class property name should be in camelCase.
   
     5 │         protected CONSTANT_CASE: unknown,
     6 │ 
@@ -62,9 +58,5 @@ invalidParameterProperty.ts:7:16 lint/style/useNamingConvention ━━━━━
     8 │     ) {}
     9 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidSyllabary.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidSyllabary.js.snap
index fb2b3efab9ea..c582916a1ff6 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidSyllabary.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidSyllabary.js.snap
@@ -21,7 +21,7 @@ expression: invalidSyllabary.js
 ```
 invalidSyllabary.js:2:11 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This top-level const name should be in camelCase or PascalCase or CONSTANT_CASE.
+  ! This global const name should be in camelCase or PascalCase or CONSTANT_CASE.
   
     1 │ {
   > 2 │     const 안녕a하세요 = 0;
@@ -60,5 +60,3 @@ invalidSyllabary.js:10:11 lint/style/useNamingConvention ━━━━━━━
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTopLevelVariable.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTopLevelVariable.ts.snap
index 7a4613fbe04a..57435e8dcb08 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTopLevelVariable.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTopLevelVariable.ts.snap
@@ -26,22 +26,20 @@ export const fooYPosition = 0;
 ```
 invalidTopLevelVariable.ts:1:14 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This top-level const name should be in camelCase or PascalCase or CONSTANT_CASE.
+  ! This global const name should be in camelCase or PascalCase or CONSTANT_CASE.
   
   > 1 │ export const Unknown_Style = 0
       │              ^^^^^^^^^^^^^
     2 │ export const MY__CONSTANT = 0
     3 │ 
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
 ```
 invalidTopLevelVariable.ts:2:14 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This top-level const name should be in camelCase or PascalCase or CONSTANT_CASE.
+  ! This global const name should be in camelCase or PascalCase or CONSTANT_CASE.
   
     1 │ export const Unknown_Style = 0
   > 2 │ export const MY__CONSTANT = 0
@@ -49,15 +47,13 @@ invalidTopLevelVariable.ts:2:14 lint/style/useNamingConvention ━━━━━
     3 │ 
     4 │ export var Unknown_Style_1 = 0
   
-  i The name could be renamed to `myConstant`.
-  
 
 ```
 
 ```
 invalidTopLevelVariable.ts:4:12 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This top-level var name should be in camelCase or PascalCase or CONSTANT_CASE.
+  ! This global var name should be in camelCase or PascalCase or CONSTANT_CASE.
   
     2 │ export const MY__CONSTANT = 0
     3 │ 
@@ -66,15 +62,13 @@ invalidTopLevelVariable.ts:4:12 lint/style/useNamingConvention ━━━━━
     5 │ 
     6 │ export let Unknown_Style_2 = 0
   
-  i The name could be renamed to `unknownStyle1`.
-  
 
 ```
 
 ```
 invalidTopLevelVariable.ts:6:12 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This top-level let name should be in camelCase or PascalCase.
+  ! This let name should be in camelCase or PascalCase.
   
     4 │ export var Unknown_Style_1 = 0
     5 │ 
@@ -83,15 +77,13 @@ invalidTopLevelVariable.ts:6:12 lint/style/useNamingConvention ━━━━━
     7 │ 
     8 │ export namespace X {
   
-  i The name could be renamed to `unknownStyle2`.
-  
 
 ```
 
 ```
 invalidTopLevelVariable.ts:9:18 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This top-level const name should be in camelCase or PascalCase or CONSTANT_CASE.
+  ! This global const name should be in camelCase or PascalCase or CONSTANT_CASE.
   
      8 │ export namespace X {
    > 9 │     export const Unknown_Style = 0
@@ -99,15 +91,13 @@ invalidTopLevelVariable.ts:9:18 lint/style/useNamingConvention ━━━━━
     10 │ 
     11 │     export var Unknown_Style_1 = 0
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
 ```
 invalidTopLevelVariable.ts:11:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This top-level var name should be in camelCase or PascalCase or CONSTANT_CASE.
+  ! This global var name should be in camelCase or PascalCase or CONSTANT_CASE.
   
      9 │     export const Unknown_Style = 0
     10 │ 
@@ -116,15 +106,13 @@ invalidTopLevelVariable.ts:11:16 lint/style/useNamingConvention ━━━━━
     12 │ 
     13 │     export let Unknown_Style_2 = 0
   
-  i The name could be renamed to `unknownStyle1`.
-  
 
 ```
 
 ```
 invalidTopLevelVariable.ts:13:16 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This top-level let name should be in camelCase or PascalCase.
+  ! This let name should be in camelCase or PascalCase.
   
     11 │     export var Unknown_Style_1 = 0
     12 │ 
@@ -133,22 +121,20 @@ invalidTopLevelVariable.ts:13:16 lint/style/useNamingConvention ━━━━━
     14 │ }
     15 │ 
   
-  i The name could be renamed to `unknownStyle2`.
-  
 
 ```
 
 ```
 invalidTopLevelVariable.ts:16:14 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! Two consecutive uppercase characters are not allowed in camelCase and PascalCase because strictCase is set to `true`.
+  ! Two consecutive uppercase characters are not allowed in camelCase because strictCase is set to `true`.
   
     14 │ }
     15 │ 
   > 16 │ export const fooYPosition = 0;
        │              ^^^^^^^^^^^^
   
-  i If you want to use consecutive uppercase characters in camelCase and PascalCase, then set the strictCase option to `false`.
+  i If you want to use consecutive uppercase characters in camelCase, then set the strictCase option to `false`.
     See the rule options for more details.
   
 
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeAlias.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeAlias.ts.snap
index 78e3f874fee3..fc538564b832 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeAlias.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeAlias.ts.snap
@@ -32,8 +32,6 @@ invalidTypeAlias.ts:1:13 lint/style/useNamingConvention ━━━━━━━━
     2 │ 
     3 │ export type CONSTANT_CASE = {}
   
-  i The name could be renamed to `CamelCase`.
-  
 
 ```
 
@@ -49,8 +47,6 @@ invalidTypeAlias.ts:3:13 lint/style/useNamingConvention ━━━━━━━━
     4 │ 
     5 │ export type snake_case = {}
   
-  i The name could be renamed to `ConstantCase`.
-  
 
 ```
 
@@ -66,8 +62,6 @@ invalidTypeAlias.ts:5:13 lint/style/useNamingConvention ━━━━━━━━
     6 │ 
     7 │ export type Unknown_Style = {}
   
-  i The name could be renamed to `SnakeCase`.
-  
 
 ```
 
@@ -83,25 +77,21 @@ invalidTypeAlias.ts:7:13 lint/style/useNamingConvention ━━━━━━━━
     8 │ 
     9 │ type _CONSTANT_CASE = {}
   
-  i The name could be renamed to `UnknownStyle`.
-  
 
 ```
 
 ```
-invalidTypeAlias.ts:9:6 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidTypeAlias.ts:9:7 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This type alias name trimmed as `CONSTANT_CASE` should be in PascalCase.
+  ! This type alias name part should be in PascalCase.
   
      7 │ export type Unknown_Style = {}
      8 │ 
    > 9 │ type _CONSTANT_CASE = {}
-       │      ^^^^^^^^^^^^^^
+       │       ^^^^^^^^^^^^^
     10 │ 
     11 │ type _snake_case = {}
   
-  i The name could be renamed to `_ConstantCase`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
      7  7 │   export type Unknown_Style = {}
@@ -115,19 +105,17 @@ invalidTypeAlias.ts:9:6 lint/style/useNamingConvention  FIXABLE  ━━━━━
 ```
 
 ```
-invalidTypeAlias.ts:11:6 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidTypeAlias.ts:11:7 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This type alias name trimmed as `snake_case` should be in PascalCase.
+  ! This type alias name part should be in PascalCase.
   
      9 │ type _CONSTANT_CASE = {}
     10 │ 
   > 11 │ type _snake_case = {}
-       │      ^^^^^^^^^^^
+       │       ^^^^^^^^^^
     12 │ 
     13 │ type _Unknown_Style = {}
   
-  i The name could be renamed to `_SnakeCase`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
      9  9 │   type _CONSTANT_CASE = {}
@@ -141,19 +129,17 @@ invalidTypeAlias.ts:11:6 lint/style/useNamingConvention  FIXABLE  ━━━━
 ```
 
 ```
-invalidTypeAlias.ts:13:6 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+invalidTypeAlias.ts:13:7 lint/style/useNamingConvention  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This type alias name trimmed as `Unknown_Style` should be in PascalCase.
+  ! This type alias name part should be in PascalCase.
   
     11 │ type _snake_case = {}
     12 │ 
   > 13 │ type _Unknown_Style = {}
-       │      ^^^^^^^^^^^^^^
+       │       ^^^^^^^^^^^^^
     14 │ 
     15 │ type str = string
   
-  i The name could be renamed to `_UnknownStyle`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
     11 11 │   type _snake_case = {}
@@ -176,8 +162,6 @@ invalidTypeAlias.ts:15:6 lint/style/useNamingConvention  FIXABLE  ━━━━
   > 15 │ type str = string
        │      ^^^
   
-  i The name could be renamed to `Str`.
-  
   i Safe fix: Rename this symbol in PascalCase.
   
     13 13 │   type _Unknown_Style = {}
@@ -187,5 +171,3 @@ invalidTypeAlias.ts:15:6 lint/style/useNamingConvention  FIXABLE  ━━━━
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeGetter.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeGetter.ts.snap
index 7207dcccf73e..89692065932f 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeGetter.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeGetter.ts.snap
@@ -25,8 +25,6 @@ invalidTypeGetter.ts:2:9 lint/style/useNamingConvention ━━━━━━━━
     3 │ 
     4 │     get special_property(): unknown
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -42,8 +40,6 @@ invalidTypeGetter.ts:4:9 lint/style/useNamingConvention ━━━━━━━━
     5 │ 
     6 │     get Unknown_Style(): unknown
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -58,9 +54,5 @@ invalidTypeGetter.ts:6:9 lint/style/useNamingConvention ━━━━━━━━
       │         ^^^^^^^^^^^^^
     7 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeMethod.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeMethod.ts.snap
index 16ccb57de429..91e11aafc509 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeMethod.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeMethod.ts.snap
@@ -27,15 +27,13 @@ invalidTypeMethod.ts:2:5 lint/style/useNamingConvention ━━━━━━━━
     3 │ 
     4 │     AMethod(): unknown
   
-  i The name could be renamed to `method`.
-  
 
 ```
 
 ```
 invalidTypeMethod.ts:4:5 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  ! This method name should be in camelCase.
+  ! Two consecutive uppercase characters are not allowed in PascalCase because strictCase is set to `true`.
   
     2 │     METHOD(): unknown
     3 │ 
@@ -44,7 +42,8 @@ invalidTypeMethod.ts:4:5 lint/style/useNamingConvention ━━━━━━━━
     5 │ 
     6 │     method_1(): unknown
   
-  i The name could be renamed to `aMethod`.
+  i If you want to use consecutive uppercase characters in PascalCase, then set the strictCase option to `false`.
+    See the rule options for more details.
   
 
 ```
@@ -61,8 +60,6 @@ invalidTypeMethod.ts:6:5 lint/style/useNamingConvention ━━━━━━━━
     7 │ 
     8 │     Unknown_Style(): unknown
   
-  i The name could be renamed to `method1`.
-  
 
 ```
 
@@ -77,9 +74,5 @@ invalidTypeMethod.ts:8:5 lint/style/useNamingConvention ━━━━━━━━
       │     ^^^^^^^^^^^^^
     9 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeParameter.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeParameter.ts.snap
index 038c32e94909..49727ad277c3 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeParameter.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeParameter.ts.snap
@@ -22,8 +22,6 @@ invalidTypeParameter.ts:1:23 lint/style/useNamingConvention ━━━━━━
     2 │ 
     3 │ type Mapped<T> = {
   
-  i The name could be renamed to `L`.
-  
 
 ```
 
@@ -37,8 +35,6 @@ invalidTypeParameter.ts:1:26 lint/style/useNamingConvention ━━━━━━
     2 │ 
     3 │ type Mapped<T> = {
   
-  i The name could be renamed to `L1`.
-  
 
 ```
 
@@ -52,8 +48,6 @@ invalidTypeParameter.ts:1:30 lint/style/useNamingConvention ━━━━━━
     2 │ 
     3 │ type Mapped<T> = {
   
-  i The name could be renamed to `CamelCase`.
-  
 
 ```
 
@@ -67,8 +61,6 @@ invalidTypeParameter.ts:1:41 lint/style/useNamingConvention ━━━━━━
     2 │ 
     3 │ type Mapped<T> = {
   
-  i The name could be renamed to `ConstantCase`.
-  
 
 ```
 
@@ -82,8 +74,6 @@ invalidTypeParameter.ts:1:56 lint/style/useNamingConvention ━━━━━━
     2 │ 
     3 │ type Mapped<T> = {
   
-  i The name could be renamed to `SnakeCase`.
-  
 
 ```
 
@@ -97,8 +87,6 @@ invalidTypeParameter.ts:1:68 lint/style/useNamingConvention ━━━━━━
     2 │ 
     3 │ type Mapped<T> = {
   
-  i The name could be renamed to `UnknownStyle`.
-  
 
 ```
 
@@ -112,9 +100,5 @@ invalidTypeParameter.ts:4:6 lint/style/useNamingConvention ━━━━━━━
       │      ^
     5 │ }
   
-  i The name could be renamed to `K`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeProperty.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeProperty.ts.snap
index f8e8173e89b1..d7774a1b321a 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeProperty.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeProperty.ts.snap
@@ -31,8 +31,6 @@ invalidTypeProperty.ts:2:5 lint/style/useNamingConvention ━━━━━━━
     3 │ 
     4 │     SpecialProperty: unknown
   
-  i The name could be renamed to `initialized`.
-  
 
 ```
 
@@ -48,8 +46,6 @@ invalidTypeProperty.ts:4:5 lint/style/useNamingConvention ━━━━━━━
     5 │ 
     6 │     special_property: unknown
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -65,8 +61,6 @@ invalidTypeProperty.ts:6:5 lint/style/useNamingConvention ━━━━━━━
     7 │ 
     8 │     Unknown_Style: unknown
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -82,8 +76,6 @@ invalidTypeProperty.ts:8:5 lint/style/useNamingConvention ━━━━━━━
      9 │ 
     10 │     Unknown_Init_Style: unknown
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
@@ -99,8 +91,6 @@ invalidTypeProperty.ts:10:5 lint/style/useNamingConvention ━━━━━━━
     11 │ 
     12 │     A_CONSTANT: unknown
   
-  i The name could be renamed to `unknownInitStyle`.
-  
 
 ```
 
@@ -115,9 +105,5 @@ invalidTypeProperty.ts:12:5 lint/style/useNamingConvention ━━━━━━━
        │     ^^^^^^^^^^
     13 │ }
   
-  i The name could be renamed to `aConstant`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeReadonlyProperty.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeReadonlyProperty.ts.snap
index 126573a2e2ac..9e9d81df7dce 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeReadonlyProperty.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeReadonlyProperty.ts.snap
@@ -29,8 +29,6 @@ invalidTypeReadonlyProperty.ts:2:14 lint/style/useNamingConvention ━━━━
     3 │ 
     4 │     readonly SpecialProperty: unknown
   
-  i The name could be renamed to `initialized`.
-  
 
 ```
 
@@ -46,8 +44,6 @@ invalidTypeReadonlyProperty.ts:4:14 lint/style/useNamingConvention ━━━━
     5 │ 
     6 │     readonly special_property: unknown
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -63,8 +59,6 @@ invalidTypeReadonlyProperty.ts:6:14 lint/style/useNamingConvention ━━━━
     7 │ 
     8 │     readonly Unknown_Style: unknown
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -80,8 +74,6 @@ invalidTypeReadonlyProperty.ts:8:14 lint/style/useNamingConvention ━━━━
      9 │ 
     10 │     readonly Unknown_Init_Style: unknown
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
 
@@ -96,9 +88,5 @@ invalidTypeReadonlyProperty.ts:10:14 lint/style/useNamingConvention ━━━━
        │              ^^^^^^^^^^^^^^^^^^
     11 │ }
   
-  i The name could be renamed to `unknownInitStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeSetter.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeSetter.ts.snap
index 2d013b73ac74..5f9af1b3197e 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeSetter.ts.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidTypeSetter.ts.snap
@@ -29,8 +29,6 @@ invalidTypeSetter.ts:2:9 lint/style/useNamingConvention ━━━━━━━━
     3 │ 
     4 │     set PROPERTY(x: unknown )
   
-  i The name could be renamed to `x`.
-  
 
 ```
 
@@ -46,8 +44,6 @@ invalidTypeSetter.ts:4:9 lint/style/useNamingConvention ━━━━━━━━
     5 │ 
     6 │     set SpecialProperty(x: unknown )
   
-  i The name could be renamed to `property`.
-  
 
 ```
 
@@ -63,8 +59,6 @@ invalidTypeSetter.ts:6:9 lint/style/useNamingConvention ━━━━━━━━
     7 │ 
     8 │     set special_property(x: unknown )
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -80,8 +74,6 @@ invalidTypeSetter.ts:8:9 lint/style/useNamingConvention ━━━━━━━━
      9 │ 
     10 │     set Unknown_Style(x: unknown )
   
-  i The name could be renamed to `specialProperty`.
-  
 
 ```
 
@@ -96,9 +88,5 @@ invalidTypeSetter.ts:10:9 lint/style/useNamingConvention ━━━━━━━
        │         ^^^^^^^^^^^^^
     11 │ }
   
-  i The name could be renamed to `unknownStyle`.
-  
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/malformedOptions.js.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/malformedOptions.js.snap
index d927f5069d9f..f86b2ed4db69 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/malformedOptions.js.snap
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/malformedOptions.js.snap
@@ -11,22 +11,22 @@ expression: malformedOptions.js
 ```
 malformedOptions.options:9:25 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
-  × Found an unknown value `snake_case`.
+  × Found an unknown value `kebab-case`.
   
      7 │ 					"level": "error",
      8 │ 					"options": {
-   > 9 │ 						"enumMemberCase": "snake_case"
+   > 9 │ 						"enumMemberCase": "kebab-case"
        │ 						                  ^^^^^^^^^^^^
     10 │ 					}
     11 │ 				}
   
   i Accepted values:
   
-  - PascalCase
-  - CONSTANT_CASE
   - camelCase
+  - CONSTANT_CASE
+  - PascalCase
+  - snake_case
+  - unknown
   
 
 ```
-
-
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/malformedOptions.options.json b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/malformedOptions.options.json
index fec3ee98566f..8928f09d9cfa 100644
--- a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/malformedOptions.options.json
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/malformedOptions.options.json
@@ -6,7 +6,7 @@
 				"useNamingConvention": {
 					"level": "error",
 					"options": {
-						"enumMemberCase": "snake_case"
+						"enumMemberCase": "kebab-case"
 					}
 				}
 			}
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyle.options.json b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyle.options.json
new file mode 100644
index 000000000000..6a5b7b3f2914
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyle.options.json
@@ -0,0 +1,19 @@
+{
+	"$schema": "../../../../../../packages/@biomejs/biome/configuration_schema.json",
+	"linter": {
+		"rules": {
+			"style": {
+				"useNamingConvention": {
+					"level": "error",
+					"options": {
+                        "custom": [
+							{
+								"match": "aSepcial_CASE|(.*)"
+							}
+                        ]
+					}
+				}
+			}
+		}
+	}
+}
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyle.ts b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyle.ts
new file mode 100644
index 000000000000..0dd558934d01
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyle.ts
@@ -0,0 +1 @@
+const aSepcial_CASE = 0;
\ No newline at end of file
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyle.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyle.ts.snap
new file mode 100644
index 000000000000..b35cfefca222
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyle.ts.snap
@@ -0,0 +1,8 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: validCustomStyle.ts
+---
+# Input
+```ts
+const aSepcial_CASE = 0;
+```
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleExceptions.options.json b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleExceptions.options.json
new file mode 100644
index 000000000000..6a5b7b3f2914
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleExceptions.options.json
@@ -0,0 +1,19 @@
+{
+	"$schema": "../../../../../../packages/@biomejs/biome/configuration_schema.json",
+	"linter": {
+		"rules": {
+			"style": {
+				"useNamingConvention": {
+					"level": "error",
+					"options": {
+                        "custom": [
+							{
+								"match": "aSepcial_CASE|(.*)"
+							}
+                        ]
+					}
+				}
+			}
+		}
+	}
+}
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleExceptions.ts b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleExceptions.ts
new file mode 100644
index 000000000000..0dd558934d01
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleExceptions.ts
@@ -0,0 +1 @@
+const aSepcial_CASE = 0;
\ No newline at end of file
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleExceptions.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleExceptions.ts.snap
new file mode 100644
index 000000000000..edb826a29cb9
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleExceptions.ts.snap
@@ -0,0 +1,8 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: validCustomStyleExceptions.ts
+---
+# Input
+```ts
+const aSepcial_CASE = 0;
+```
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleUnderscorePrivate.options.json b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleUnderscorePrivate.options.json
new file mode 100644
index 000000000000..2eb21d755de2
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleUnderscorePrivate.options.json
@@ -0,0 +1,24 @@
+{
+	"$schema": "../../../../../../packages/@biomejs/biome/configuration_schema.json",
+	"linter": {
+		"rules": {
+			"style": {
+				"useNamingConvention": {
+					"level": "error",
+					"options": {
+                        "custom": [
+                            {
+                                "selector": {
+									"kind": "memberLike",
+                                	"modifiers": ["private"]
+								},
+								"match": "_(.*)",
+                                "formats": ["snake_case"]
+                            }
+                        ]
+					}
+				}
+			}
+		}
+	}
+}
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleUnderscorePrivate.ts b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleUnderscorePrivate.ts
new file mode 100644
index 000000000000..f5123c239202
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleUnderscorePrivate.ts
@@ -0,0 +1,3 @@
+class X {
+    private _private: number
+}
\ No newline at end of file
diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleUnderscorePrivate.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleUnderscorePrivate.ts.snap
new file mode 100644
index 000000000000..222298ed96b3
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/validCustomStyleUnderscorePrivate.ts.snap
@@ -0,0 +1,10 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: validCustomStyleUnderscorePrivate.ts
+---
+# Input
+```ts
+class X {
+    private _private: number
+}
+```
diff --git a/crates/biome_js_formatter/src/utils/format_modifiers.rs b/crates/biome_js_formatter/src/utils/format_modifiers.rs
index a4b76b385d27..501aa761bf77 100644
--- a/crates/biome_js_formatter/src/utils/format_modifiers.rs
+++ b/crates/biome_js_formatter/src/utils/format_modifiers.rs
@@ -3,7 +3,7 @@ use crate::utils::sort_modifiers_by_precedence;
 use crate::{AsFormat, IntoFormat};
 use biome_formatter::{format_args, write};
 use biome_js_syntax::JsSyntaxKind::JS_DECORATOR;
-use biome_js_syntax::{JsLanguage, Modifiers};
+use biome_js_syntax::{JsLanguage, Modifier};
 use biome_rowan::{AstNode, AstNodeList, NodeOrToken};
 
 pub(crate) struct FormatModifiers<List> {
@@ -20,7 +20,7 @@ impl<List, Node> Format<JsFormatContext> for FormatModifiers<List>
 where
     Node: AstNode<Language = JsLanguage> + AsFormat<JsFormatContext> + IntoFormat<JsFormatContext>,
     List: AstNodeList<Language = JsLanguage, Node = Node>,
-    Modifiers: for<'a> From<&'a Node>,
+    Modifier: for<'a> From<&'a Node>,
 {
     fn fmt(&self, f: &mut Formatter<JsFormatContext>) -> FormatResult<()> {
         let modifiers = sort_modifiers_by_precedence(&self.list);
diff --git a/crates/biome_js_formatter/src/utils/mod.rs b/crates/biome_js_formatter/src/utils/mod.rs
index 516f6a826e95..860751c15b4b 100644
--- a/crates/biome_js_formatter/src/utils/mod.rs
+++ b/crates/biome_js_formatter/src/utils/mod.rs
@@ -32,7 +32,7 @@ pub(crate) use binary_like_expression::{
 use biome_formatter::{format_args, write, Buffer};
 use biome_js_syntax::JsSyntaxToken;
 use biome_js_syntax::{
-    AnyJsExpression, AnyJsStatement, JsCallExpression, JsInitializerClause, JsLanguage, Modifiers,
+    AnyJsExpression, AnyJsStatement, JsCallExpression, JsInitializerClause, JsLanguage, Modifier,
 };
 use biome_rowan::{AstNode, AstNodeList};
 use biome_text_size::TextSize;
@@ -206,11 +206,11 @@ pub(crate) fn sort_modifiers_by_precedence<List, Node>(list: &List) -> Vec<Node>
 where
     Node: AstNode<Language = JsLanguage>,
     List: AstNodeList<Language = JsLanguage, Node = Node>,
-    Modifiers: for<'a> From<&'a Node>,
+    Modifier: for<'a> From<&'a Node>,
 {
     let mut nodes_and_modifiers = list.iter().collect::<Vec<Node>>();
 
-    nodes_and_modifiers.sort_unstable_by_key(|node| Modifiers::from(node));
+    nodes_and_modifiers.sort_unstable_by_key(|node| Modifier::from(node));
 
     nodes_and_modifiers
 }
diff --git a/crates/biome_js_syntax/Cargo.toml b/crates/biome_js_syntax/Cargo.toml
index 6b2cd3d4da29..95ca4d82e203 100644
--- a/crates/biome_js_syntax/Cargo.toml
+++ b/crates/biome_js_syntax/Cargo.toml
@@ -12,6 +12,8 @@ version              = "0.5.7"
 
 [dependencies]
 biome_rowan = { workspace = true }
+bitflags    = { workspace = true }
+enumflags2  = { workspace = true }
 schemars    = { workspace = true, optional = true }
 serde       = { workspace = true, features = ["derive"] }
 
diff --git a/crates/biome_js_syntax/src/class_member_ext.rs b/crates/biome_js_syntax/src/class_member_ext.rs
new file mode 100644
index 000000000000..bf09adfef362
--- /dev/null
+++ b/crates/biome_js_syntax/src/class_member_ext.rs
@@ -0,0 +1,100 @@
+use crate::{
+    AnyJsMethodModifier, AnyJsPropertyModifier, AnyTsMethodSignatureModifier,
+    AnyTsPropertySignatureModifier, JsMethodModifierList, JsPropertyModifierList, JsSyntaxKind,
+    TsAccessibilityModifier, TsMethodSignatureModifierList, TsPropertySignatureModifierList,
+};
+
+bitflags::bitflags! {
+    #[derive(Debug, Copy, Default, Clone, Hash, Eq, PartialEq)]
+    pub struct Modifiers: u16 {
+        const ABSTRACT = 1 << 0;
+        const ACCESSOR = 1 << 1;
+        const DECLARE = 1 << 2;
+        const DECORATED = 1 << 3;
+        const OVERRIDE = 1 << 4;
+        const PRIVATE = 1 << 5;
+        const PROTECTED = 1 << 6;
+        const PUBLIC = 1 << 7;
+        const READONLY = 1 << 8;
+        const STATIC = 1 << 9;
+    }
+}
+impl From<TsAccessibilityModifier> for Modifiers {
+    fn from(value: TsAccessibilityModifier) -> Self {
+        if let Ok(modifier_token) = value.modifier_token() {
+            match modifier_token.kind() {
+                JsSyntaxKind::PRIVATE_KW => Self::PRIVATE,
+                JsSyntaxKind::PROTECTED_KW => Self::PROTECTED,
+                JsSyntaxKind::PUBLIC_KW => Self::PUBLIC,
+                _ => Self::empty(),
+            }
+        } else {
+            Self::empty()
+        }
+    }
+}
+impl From<JsMethodModifierList> for Modifiers {
+    fn from(value: JsMethodModifierList) -> Self {
+        let mut result = Self::empty();
+        for modifier in value {
+            result |= match modifier {
+                AnyJsMethodModifier::JsStaticModifier(_) => Self::STATIC,
+                AnyJsMethodModifier::TsAccessibilityModifier(modifier) => modifier.into(),
+                AnyJsMethodModifier::JsDecorator(_) => Self::DECORATED,
+                AnyJsMethodModifier::TsOverrideModifier(_) => Self::OVERRIDE,
+            };
+        }
+        result
+    }
+}
+impl From<JsPropertyModifierList> for Modifiers {
+    fn from(value: JsPropertyModifierList) -> Self {
+        let mut result = Self::empty();
+        for modifier in value {
+            result |= match modifier {
+                AnyJsPropertyModifier::JsStaticModifier(_) => Self::STATIC,
+                AnyJsPropertyModifier::TsAccessibilityModifier(modifier) => modifier.into(),
+                AnyJsPropertyModifier::TsReadonlyModifier(_) => Self::READONLY,
+                AnyJsPropertyModifier::JsAccessorModifier(_) => Self::ACCESSOR,
+                AnyJsPropertyModifier::JsDecorator(_) => Self::DECORATED,
+                AnyJsPropertyModifier::TsOverrideModifier(_) => Self::OVERRIDE,
+            };
+        }
+        result
+    }
+}
+impl From<TsPropertySignatureModifierList> for Modifiers {
+    fn from(value: TsPropertySignatureModifierList) -> Self {
+        let mut result = Self::empty();
+        for modifier in value {
+            result |= match modifier {
+                AnyTsPropertySignatureModifier::JsStaticModifier(_) => Self::STATIC,
+                AnyTsPropertySignatureModifier::TsAccessibilityModifier(modifier) => {
+                    modifier.into()
+                }
+                AnyTsPropertySignatureModifier::TsReadonlyModifier(_) => Self::READONLY,
+                AnyTsPropertySignatureModifier::TsAbstractModifier(_) => Self::ABSTRACT,
+                AnyTsPropertySignatureModifier::JsAccessorModifier(_) => Self::ACCESSOR,
+                AnyTsPropertySignatureModifier::TsDeclareModifier(_) => Self::DECLARE,
+                AnyTsPropertySignatureModifier::JsDecorator(_) => Self::DECORATED,
+                AnyTsPropertySignatureModifier::TsOverrideModifier(_) => Self::OVERRIDE,
+            };
+        }
+        result
+    }
+}
+impl From<TsMethodSignatureModifierList> for Modifiers {
+    fn from(value: TsMethodSignatureModifierList) -> Self {
+        let mut result = Self::empty();
+        for modifier in value {
+            result |= match modifier {
+                AnyTsMethodSignatureModifier::JsStaticModifier(_) => Self::STATIC,
+                AnyTsMethodSignatureModifier::TsAccessibilityModifier(modifier) => modifier.into(),
+                AnyTsMethodSignatureModifier::TsAbstractModifier(_) => Self::ABSTRACT,
+                AnyTsMethodSignatureModifier::JsDecorator(_) => Self::DECORATED,
+                AnyTsMethodSignatureModifier::TsOverrideModifier(_) => Self::OVERRIDE,
+            };
+        }
+        result
+    }
+}
diff --git a/crates/biome_js_syntax/src/lib.rs b/crates/biome_js_syntax/src/lib.rs
index cb8c8c640670..7fd5bcb98513 100644
--- a/crates/biome_js_syntax/src/lib.rs
+++ b/crates/biome_js_syntax/src/lib.rs
@@ -6,6 +6,7 @@
 mod generated;
 pub mod assign_ext;
 pub mod binding_ext;
+pub mod class_member_ext;
 pub mod declaration_ext;
 pub mod directive_ext;
 pub mod export_ext;
diff --git a/crates/biome_js_syntax/src/modifier_ext.rs b/crates/biome_js_syntax/src/modifier_ext.rs
index b626a1d57806..c3c18c11dfe7 100644
--- a/crates/biome_js_syntax/src/modifier_ext.rs
+++ b/crates/biome_js_syntax/src/modifier_ext.rs
@@ -1,15 +1,24 @@
+use biome_rowan::AstNodeList;
+use enumflags2::BitFlags;
+
 use crate::{
     AnyJsMethodModifier, AnyJsPropertyModifier, AnyTsIndexSignatureModifier,
     AnyTsMethodSignatureModifier, AnyTsPropertyParameterModifier, AnyTsPropertySignatureModifier,
-    AnyTsTypeParameterModifier, JsSyntaxKind, TsAccessibilityModifier,
+    AnyTsTypeParameterModifier, JsMethodModifierList, JsPropertyModifierList, JsSyntaxKind,
+    TsAccessibilityModifier, TsMethodSignatureModifierList, TsPropertySignatureModifierList,
 };
 
 /// Helpful data structure to make the order of modifiers predictable inside the formatter
-#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
-pub enum Modifiers {
+#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
+#[enumflags2::bitflags]
+#[repr(u16)]
+pub enum Modifier {
     // modifiers must be sorted by precedence.
     Decorator,
-    Accessibility,
+    BogusAccessibility,
+    Private,
+    Protected,
+    Public,
     Declare,
     Static,
     Abstract,
@@ -18,76 +27,152 @@ pub enum Modifiers {
     Accessor,
 }
 
-impl From<&AnyTsIndexSignatureModifier> for Modifiers {
+impl std::fmt::Display for Modifier {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "{}",
+            match self {
+                Modifier::Decorator => "decorator",
+                Modifier::BogusAccessibility => "accessibility",
+                Modifier::Private => "private",
+                Modifier::Protected => "protected",
+                Modifier::Public => "public",
+                Modifier::Declare => "declare",
+                Modifier::Static => "static",
+                Modifier::Abstract => "abstract",
+                Modifier::Override => "override",
+                Modifier::Readonly => "readonly",
+                Modifier::Accessor => "accessor",
+            }
+        )
+    }
+}
+
+impl From<&AnyTsIndexSignatureModifier> for Modifier {
     fn from(modifier: &AnyTsIndexSignatureModifier) -> Self {
         match modifier {
-            AnyTsIndexSignatureModifier::JsStaticModifier(_) => Modifiers::Static,
-            AnyTsIndexSignatureModifier::TsReadonlyModifier(_) => Modifiers::Readonly,
+            AnyTsIndexSignatureModifier::JsStaticModifier(_) => Modifier::Static,
+            AnyTsIndexSignatureModifier::TsReadonlyModifier(_) => Modifier::Readonly,
         }
     }
 }
 
-impl From<&AnyJsMethodModifier> for Modifiers {
+impl From<&AnyJsMethodModifier> for Modifier {
     fn from(modifier: &AnyJsMethodModifier) -> Self {
         match modifier {
-            AnyJsMethodModifier::JsDecorator(_) => Modifiers::Decorator,
-            AnyJsMethodModifier::JsStaticModifier(_) => Modifiers::Static,
-            AnyJsMethodModifier::TsAccessibilityModifier(_) => Modifiers::Accessibility,
-            AnyJsMethodModifier::TsOverrideModifier(_) => Modifiers::Override,
+            AnyJsMethodModifier::JsDecorator(_) => Modifier::Decorator,
+            AnyJsMethodModifier::JsStaticModifier(_) => Modifier::Static,
+            AnyJsMethodModifier::TsAccessibilityModifier(accessibility) => accessibility.into(),
+            AnyJsMethodModifier::TsOverrideModifier(_) => Modifier::Override,
         }
     }
 }
 
-impl From<&AnyTsMethodSignatureModifier> for Modifiers {
+impl From<&AnyTsMethodSignatureModifier> for Modifier {
     fn from(modifier: &AnyTsMethodSignatureModifier) -> Self {
         match modifier {
-            AnyTsMethodSignatureModifier::JsDecorator(_) => Modifiers::Decorator,
-            AnyTsMethodSignatureModifier::JsStaticModifier(_) => Modifiers::Static,
-            AnyTsMethodSignatureModifier::TsAbstractModifier(_) => Modifiers::Abstract,
-            AnyTsMethodSignatureModifier::TsAccessibilityModifier(_) => Modifiers::Accessibility,
-            AnyTsMethodSignatureModifier::TsOverrideModifier(_) => Modifiers::Override,
+            AnyTsMethodSignatureModifier::JsDecorator(_) => Modifier::Decorator,
+            AnyTsMethodSignatureModifier::JsStaticModifier(_) => Modifier::Static,
+            AnyTsMethodSignatureModifier::TsAbstractModifier(_) => Modifier::Abstract,
+            AnyTsMethodSignatureModifier::TsAccessibilityModifier(accessibility) => {
+                accessibility.into()
+            }
+            AnyTsMethodSignatureModifier::TsOverrideModifier(_) => Modifier::Override,
         }
     }
 }
 
-impl From<&AnyJsPropertyModifier> for Modifiers {
+impl From<&AnyJsPropertyModifier> for Modifier {
     fn from(modifier: &AnyJsPropertyModifier) -> Self {
         match modifier {
-            AnyJsPropertyModifier::JsDecorator(_) => Modifiers::Decorator,
-            AnyJsPropertyModifier::JsStaticModifier(_) => Modifiers::Static,
-            AnyJsPropertyModifier::JsAccessorModifier(_) => Modifiers::Accessor,
-            AnyJsPropertyModifier::TsAccessibilityModifier(_) => Modifiers::Accessibility,
-            AnyJsPropertyModifier::TsOverrideModifier(_) => Modifiers::Override,
-            AnyJsPropertyModifier::TsReadonlyModifier(_) => Modifiers::Readonly,
+            AnyJsPropertyModifier::JsDecorator(_) => Modifier::Decorator,
+            AnyJsPropertyModifier::JsStaticModifier(_) => Modifier::Static,
+            AnyJsPropertyModifier::JsAccessorModifier(_) => Modifier::Accessor,
+            AnyJsPropertyModifier::TsAccessibilityModifier(accessibility) => accessibility.into(),
+            AnyJsPropertyModifier::TsOverrideModifier(_) => Modifier::Override,
+            AnyJsPropertyModifier::TsReadonlyModifier(_) => Modifier::Readonly,
         }
     }
 }
 
-impl From<&AnyTsPropertyParameterModifier> for Modifiers {
+impl From<&AnyTsPropertyParameterModifier> for Modifier {
     fn from(modifier: &AnyTsPropertyParameterModifier) -> Self {
         match modifier {
-            AnyTsPropertyParameterModifier::TsAccessibilityModifier(_) => Modifiers::Accessibility,
-            AnyTsPropertyParameterModifier::TsOverrideModifier(_) => Modifiers::Override,
-            AnyTsPropertyParameterModifier::TsReadonlyModifier(_) => Modifiers::Readonly,
+            AnyTsPropertyParameterModifier::TsAccessibilityModifier(accessibility) => {
+                accessibility.into()
+            }
+            AnyTsPropertyParameterModifier::TsOverrideModifier(_) => Modifier::Override,
+            AnyTsPropertyParameterModifier::TsReadonlyModifier(_) => Modifier::Readonly,
         }
     }
 }
 
-impl From<&AnyTsPropertySignatureModifier> for Modifiers {
+impl From<&AnyTsPropertySignatureModifier> for Modifier {
     fn from(modifier: &AnyTsPropertySignatureModifier) -> Self {
         match modifier {
-            AnyTsPropertySignatureModifier::JsDecorator(_) => Modifiers::Decorator,
-            AnyTsPropertySignatureModifier::TsAccessibilityModifier(_) => Modifiers::Accessibility,
-            AnyTsPropertySignatureModifier::TsDeclareModifier(_) => Modifiers::Declare,
-            AnyTsPropertySignatureModifier::JsStaticModifier(_) => Modifiers::Static,
-            AnyTsPropertySignatureModifier::JsAccessorModifier(_) => Modifiers::Accessor,
-            AnyTsPropertySignatureModifier::TsAbstractModifier(_) => Modifiers::Abstract,
-            AnyTsPropertySignatureModifier::TsOverrideModifier(_) => Modifiers::Override,
-            AnyTsPropertySignatureModifier::TsReadonlyModifier(_) => Modifiers::Readonly,
+            AnyTsPropertySignatureModifier::JsDecorator(_) => Modifier::Decorator,
+            AnyTsPropertySignatureModifier::TsAccessibilityModifier(accessibility) => {
+                accessibility.into()
+            }
+            AnyTsPropertySignatureModifier::TsDeclareModifier(_) => Modifier::Declare,
+            AnyTsPropertySignatureModifier::JsStaticModifier(_) => Modifier::Static,
+            AnyTsPropertySignatureModifier::JsAccessorModifier(_) => Modifier::Accessor,
+            AnyTsPropertySignatureModifier::TsAbstractModifier(_) => Modifier::Abstract,
+            AnyTsPropertySignatureModifier::TsOverrideModifier(_) => Modifier::Override,
+            AnyTsPropertySignatureModifier::TsReadonlyModifier(_) => Modifier::Readonly,
+        }
+    }
+}
+
+impl From<&TsAccessibilityModifier> for Modifier {
+    fn from(value: &TsAccessibilityModifier) -> Self {
+        if let Ok(modifier_token) = value.modifier_token() {
+            match modifier_token.kind() {
+                JsSyntaxKind::PRIVATE_KW => Self::Private,
+                JsSyntaxKind::PROTECTED_KW => Self::Protected,
+                JsSyntaxKind::PUBLIC_KW => Self::Public,
+                _ => Self::BogusAccessibility,
+            }
+        } else {
+            Self::BogusAccessibility
         }
     }
 }
 
+impl From<&JsMethodModifierList> for BitFlags<Modifier> {
+    fn from(value: &JsMethodModifierList) -> Self {
+        value
+            .iter()
+            .map(|m| Modifier::from(&m))
+            .fold(Self::empty(), |acc, m| acc | m)
+    }
+}
+impl From<&JsPropertyModifierList> for BitFlags<Modifier> {
+    fn from(value: &JsPropertyModifierList) -> Self {
+        value
+            .iter()
+            .map(|m| Modifier::from(&m))
+            .fold(Self::empty(), |acc, m| acc | m)
+    }
+}
+impl From<&TsPropertySignatureModifierList> for BitFlags<Modifier> {
+    fn from(value: &TsPropertySignatureModifierList) -> Self {
+        value
+            .iter()
+            .map(|m| Modifier::from(&m))
+            .fold(Self::empty(), |acc, m| acc | m)
+    }
+}
+impl From<&TsMethodSignatureModifierList> for BitFlags<Modifier> {
+    fn from(value: &TsMethodSignatureModifierList) -> Self {
+        value
+            .iter()
+            .map(|m| Modifier::from(&m))
+            .fold(Self::empty(), |acc, m| acc | m)
+    }
+}
+
 /// Helpful data structure to make the order of type parameter modifiers predictable inside the formatter
 #[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
 pub enum TypeParameterModifiers {
diff --git a/crates/biome_service/tests/invalid/naming_convention_incorrect_options.json.snap b/crates/biome_service/tests/invalid/naming_convention_incorrect_options.json.snap
index 55b7d413b180..3edbab314713 100644
--- a/crates/biome_service/tests/invalid/naming_convention_incorrect_options.json.snap
+++ b/crates/biome_service/tests/invalid/naming_convention_incorrect_options.json.snap
@@ -17,7 +17,5 @@ naming_convention_incorrect_options.json:9:7 deserialize ━━━━━━━
   
   - strictCase
   - requireAscii
+  - custom
   - enumMemberCase
-  
-
-
diff --git a/crates/biome_string_case/src/lib.rs b/crates/biome_string_case/src/lib.rs
index ebb4d9288dff..e47673c9dfa4 100644
--- a/crates/biome_string_case/src/lib.rs
+++ b/crates/biome_string_case/src/lib.rs
@@ -5,29 +5,36 @@
 /// Note that some cases are superset of others.
 /// For example, `Case::Camel` includes `Case::Lower`.
 /// See [Case::is_compatible_with] for more details.
-#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[repr(u16)]
 pub enum Case {
-    /// Unknown case
-    #[default]
-    Unknown,
-    /// camelCase
-    Camel,
-    // CONSTANT_CASE
-    Constant,
-    /// kebab-case
-    Kebab,
-    /// lowercase
-    Lower,
+    /// Alphanumeric Characters that cannot be in lowercase or uppercase (numbers and syllabary)
+    Uni = 1 << 0,
     /// A, B1, C42
-    NumberableCapital,
+    NumberableCapital = 1 << 1,
+    /// UPPERCASE
+    Upper = Case::NumberableCapital as u16 | 1 << 2,
+    // CONSTANT_CASE
+    Constant = Case::Upper as u16 | 1 << 3,
     /// PascalCase
-    Pascal,
+    Pascal = Case::NumberableCapital as u16 | 1 << 4,
+    /// lowercase
+    Lower = 1 << 5,
     /// snake_case
-    Snake,
-    /// Alphanumeric Characters that cannot be in lowercase or uppercase (numbers and syllabary)
-    Uni,
-    /// UPPERCASE
-    Upper,
+    Snake = Case::Lower as u16 | 1 << 6,
+    /// kebab-case
+    Kebab = Case::Lower as u16 | 1 << 7,
+    // camelCase
+    Camel = Case::Lower as u16 | 1 << 8,
+    /// Unknown case
+    #[default]
+    Unknown = Case::Camel as u16
+        | Case::Kebab as u16
+        | Case::Snake as u16
+        | Case::Pascal as u16
+        | Case::Constant as u16
+        | Case::Uni as u16
+        | 1 << 9,
 }
 
 impl Case {
@@ -151,9 +158,11 @@ impl Case {
     /// NumberableCapital ─┤                       │
     ///                    └──► Upper ─► Constant ─┤
     ///                                            ├──► Unknown
-    ///                    ┌──► Kebab ─────────────┤
+    ///                    ┌──► Camel ─────────────┤
     ///             Lower ─┤                       │
-    ///                    └──► Camel ─────────────┤
+    ///                    └──► Kebab ─────────────┤
+    ///                    │                       │
+    ///                    └──► Snake ─────────────┤
     ///                                            │
     ///               Uni ─────────────────────────┘
     /// ```
@@ -173,18 +182,7 @@ impl Case {
     /// assert!(Case::Upper.is_compatible_with(Case::Constant));
     /// ```
     pub fn is_compatible_with(self, other: Case) -> bool {
-        self == other
-            || matches!(other, Case::Unknown)
-            || matches!((self, other), |(
-                Case::Lower,
-                Case::Camel | Case::Kebab | Case::Snake,
-            )| (
-                Case::NumberableCapital,
-                Case::Constant | Case::Pascal | Case::Upper
-            ) | (
-                Case::Upper,
-                Case::Constant
-            ))
+        ((self as u16) & (other as u16)) == (self as u16)
     }
 
     /// Convert `value` to the `self` [Case].
@@ -296,6 +294,159 @@ impl std::fmt::Display for Case {
     }
 }
 
+/// Represents a set of cases.
+///
+/// An instance of [Cases] supports the binary operators `&` and `|`
+/// to intersect and unionize two sets.
+///
+/// Note that some [Case] are already sets of [Case].
+/// For example, [Case::Unknown] is a set that includes all [Case].
+/// So adding [Case::Unknown] to a [Cases] will superseed all other cases.
+///
+/// A [Cases] is iterable.
+/// A Cases iterator doesn't yield a [Case] that is covered by another [Case] in the set.
+/// See [CasesIterator] for more details.
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
+pub struct Cases(u16);
+
+impl Cases {
+    /// Create an empty set.
+    ///
+    /// You can also obtain an empty alias using [Cases::default()].
+    pub const fn empty() -> Self {
+        Self(0)
+    }
+
+    /// Returns `true` if the set is empty.
+    pub const fn is_empty(self) -> bool {
+        self.0 == 0
+    }
+
+    /// Returns `true` if all cases of `other` are contained in the current set.
+    ///
+    /// ```
+    /// use biome_string_case::{Cases, Case};
+    ///
+    /// let camel_or_kebab = (Case::Camel | Case::Kebab);
+    ///
+    /// assert!(camel_or_kebab.contains(Case::Camel));
+    /// assert!(camel_or_kebab.contains(camel_or_kebab));
+    /// ```
+    pub fn contains(self, other: impl Into<Cases>) -> bool {
+        let other = other.into();
+        self.0 & other.0 == other.0
+    }
+}
+
+impl IntoIterator for Cases {
+    type Item = Case;
+    type IntoIter = CasesIterator;
+    fn into_iter(self) -> Self::IntoIter {
+        CasesIterator { rest: self }
+    }
+}
+
+impl FromIterator<Case> for Cases {
+    fn from_iter<T: IntoIterator<Item = Case>>(iter: T) -> Self {
+        iter.into_iter()
+            .fold(Self::empty(), |result, case| result | case)
+    }
+}
+
+impl From<Case> for Cases {
+    fn from(value: Case) -> Self {
+        Self(value as u16)
+    }
+}
+
+impl<Rhs: Into<Cases>> core::ops::BitAnd<Rhs> for Cases {
+    type Output = Cases;
+    fn bitand(self, rhs: Rhs) -> Self::Output {
+        Self(self.0 & rhs.into().0)
+    }
+}
+impl core::ops::BitAnd for Case {
+    type Output = Cases;
+    fn bitand(self, rhs: Self) -> Self::Output {
+        Cases::from(self) & rhs
+    }
+}
+impl<Rhs: Into<Cases>> core::ops::BitAndAssign<Rhs> for Cases {
+    fn bitand_assign(&mut self, rhs: Rhs) {
+        self.0 &= rhs.into().0;
+    }
+}
+
+impl<Rhs: Into<Cases>> core::ops::BitOr<Rhs> for Cases {
+    type Output = Cases;
+    fn bitor(self, rhs: Rhs) -> Self::Output {
+        Self(self.0 | rhs.into().0)
+    }
+}
+impl core::ops::BitOr for Case {
+    type Output = Cases;
+    fn bitor(self, rhs: Self) -> Self::Output {
+        Cases::from(self) | rhs
+    }
+}
+impl<Rhs: Into<Cases>> core::ops::BitOrAssign<Rhs> for Cases {
+    fn bitor_assign(&mut self, rhs: Rhs) {
+        self.0 |= rhs.into().0;
+    }
+}
+
+/// An iterator of [Cases].
+///
+/// The iterator doesn't yield a [Case] that is covered by another [Case] in the iterated set.
+/// For example, if the set includes [Case::Constant] and [Case::Upper],
+/// the iterator only yields [Case::Constant] because [Case::Constant] covers [Case::Upper].
+///
+/// ```
+/// use biome_string_case::{Cases, Case};
+///
+/// let cases = (Case::Camel | Case::Kebab.into());
+/// assert_eq!(cases.into_iter().collect::<Vec<_>>().as_slice(), &[Case::Camel, Case::Kebab]);
+///
+/// let cases = (Case::Camel | Case::Kebab.into() | Case::Lower.into());
+/// assert_eq!(cases.into_iter().collect::<Vec<_>>().as_slice(), &[Case::Camel, Case::Kebab]);
+/// ```
+#[derive(Clone, Debug)]
+pub struct CasesIterator {
+    rest: Cases,
+}
+impl Iterator for CasesIterator {
+    type Item = Case;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.rest.is_empty() {
+            None
+        } else {
+            let leading_bit_index = 15u16 - (self.rest.0.leading_zeros() as u16);
+            let case = LEADING_BIT_INDEX_TO_CASE[leading_bit_index as usize];
+            self.rest.0 &= !(case as u16);
+            Some(case)
+        }
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (0, Some(6))
+    }
+}
+impl std::iter::FusedIterator for CasesIterator {}
+
+const LEADING_BIT_INDEX_TO_CASE: [Case; 10] = [
+    Case::Uni,
+    Case::NumberableCapital,
+    Case::Upper,
+    Case::Constant,
+    Case::Pascal,
+    Case::Lower,
+    Case::Snake,
+    Case::Kebab,
+    Case::Camel,
+    Case::Unknown,
+];
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -523,4 +674,134 @@ mod tests {
 
         assert_eq!(Case::Unknown.convert("Unknown_Style"), "Unknown_Style");
     }
+
+    #[test]
+    fn test_cases_iter() {
+        fn vec(value: impl Into<Cases>) -> Vec<Case> {
+            value.into().into_iter().collect::<Vec<_>>()
+        }
+
+        assert_eq!(vec(Cases::empty()).as_slice(), &[]);
+        assert_eq!(vec(Case::Unknown).as_slice(), &[Case::Unknown]);
+        assert_eq!(vec(Case::Camel).as_slice(), &[Case::Camel]);
+        assert_eq!(vec(Case::Kebab).as_slice(), &[Case::Kebab]);
+        assert_eq!(vec(Case::Snake).as_slice(), &[Case::Snake]);
+        assert_eq!(vec(Case::Lower).as_slice(), &[Case::Lower]);
+        assert_eq!(vec(Case::Pascal).as_slice(), &[Case::Pascal]);
+        assert_eq!(vec(Case::Constant).as_slice(), &[Case::Constant]);
+        assert_eq!(vec(Case::Upper).as_slice(), &[Case::Upper]);
+        assert_eq!(vec(Case::Uni).as_slice(), &[Case::Uni]);
+        assert_eq!(
+            vec(Case::NumberableCapital).as_slice(),
+            &[Case::NumberableCapital]
+        );
+
+        assert_eq!(
+            vec(Case::Unknown | Case::Camel).as_slice(),
+            &[Case::Unknown]
+        );
+        assert_eq!(
+            vec(Case::Unknown | Case::Kebab).as_slice(),
+            &[Case::Unknown]
+        );
+        assert_eq!(
+            vec(Case::Unknown | Case::Snake).as_slice(),
+            &[Case::Unknown]
+        );
+        assert_eq!(
+            vec(Case::Unknown | Case::Lower).as_slice(),
+            &[Case::Unknown]
+        );
+        assert_eq!(
+            vec(Case::Unknown | Case::Pascal).as_slice(),
+            &[Case::Unknown]
+        );
+        assert_eq!(
+            vec(Case::Unknown | Case::Constant).as_slice(),
+            &[Case::Unknown]
+        );
+        assert_eq!(
+            vec(Case::Unknown | Case::Upper).as_slice(),
+            &[Case::Unknown]
+        );
+        assert_eq!(
+            vec(Case::Unknown | Case::NumberableCapital).as_slice(),
+            &[Case::Unknown]
+        );
+        assert_eq!(vec(Case::Unknown | Case::Uni).as_slice(), &[Case::Unknown]);
+        assert_eq!(
+            vec(Case::Unknown | Case::Pascal | Case::Camel).as_slice(),
+            &[Case::Unknown]
+        );
+
+        assert_eq!(vec(Case::Camel | Case::Lower).as_slice(), &[Case::Camel]);
+        assert_eq!(vec(Case::Kebab | Case::Lower).as_slice(), &[Case::Kebab]);
+        assert_eq!(vec(Case::Snake | Case::Lower).as_slice(), &[Case::Snake]);
+
+        assert_eq!(
+            vec(Case::Constant | Case::Upper).as_slice(),
+            &[Case::Constant]
+        );
+
+        assert_eq!(
+            vec(Case::Pascal | Case::NumberableCapital).as_slice(),
+            &[Case::Pascal]
+        );
+        assert_eq!(
+            vec(Case::Constant | Case::NumberableCapital).as_slice(),
+            &[Case::Constant]
+        );
+        assert_eq!(
+            vec(Case::Upper | Case::NumberableCapital).as_slice(),
+            &[Case::Upper]
+        );
+
+        assert_eq!(
+            vec(Case::Pascal | Case::Camel).as_slice(),
+            &[Case::Camel, Case::Pascal]
+        );
+        assert_eq!(
+            vec(Case::NumberableCapital | Case::Uni).as_slice(),
+            &[Case::NumberableCapital, Case::Uni]
+        );
+
+        assert_eq!(
+            vec(Case::Pascal
+                | Case::Constant
+                | Case::Camel
+                | Case::Kebab
+                | Case::Snake
+                | Case::Uni)
+            .as_slice(),
+            &[
+                Case::Camel,
+                Case::Kebab,
+                Case::Snake,
+                Case::Pascal,
+                Case::Constant,
+                Case::Uni
+            ]
+        );
+    }
+
+    #[test]
+    fn test_leading_bit_to_case() {
+        for (i, case) in LEADING_BIT_INDEX_TO_CASE.iter().enumerate() {
+            assert_eq!(i as u16, 15u16 - (*case as u16).leading_zeros() as u16)
+        }
+    }
+
+    #[test]
+    fn test_size_hint_upper_limit() {
+        let mut cases = Cases::empty();
+        let mut max_count = 0;
+        for case in LEADING_BIT_INDEX_TO_CASE {
+            let count = (cases | case).into_iter().count();
+            if count >= max_count {
+                cases |= case;
+                max_count = count;
+            }
+        }
+        assert_eq!(cases.into_iter().size_hint().1, Some(max_count));
+    }
 }
diff --git a/packages/@biomejs/backend-jsonrpc/src/workspace.ts b/packages/@biomejs/backend-jsonrpc/src/workspace.ts
index 39e20858d19d..68f3154c1a18 100644
--- a/packages/@biomejs/backend-jsonrpc/src/workspace.ts
+++ b/packages/@biomejs/backend-jsonrpc/src/workspace.ts
@@ -1718,10 +1718,11 @@ export interface FilenamingConventionOptions {
  * Rule's options.
  */
 export interface NamingConventionOptions {
+	custom: Convention[];
 	/**
 	 * Allowed cases for _TypeScript_ `enum` member names.
 	 */
-	enumMemberCase: EnumMemberCase;
+	enumMemberCase: Format;
 	/**
 	 * If `false`, then non-ASCII characters are allowed.
 	 */
@@ -1759,10 +1760,20 @@ For example, for React's `useRef()` hook the value would be `true`, while for `u
 }
 export type ConsistentArrayType = "shorthand" | "generic";
 export type FilenameCases = FilenameCase[];
+export interface Convention {
+	formats: Formats;
+	match?: Regex;
+	selector: Selector;
+}
 /**
- * Supported cases for TypeScript `enum` member names.
+ * Supported cases.
  */
-export type EnumMemberCase = "PascalCase" | "CONSTANT_CASE" | "camelCase";
+export type Format =
+	| "camelCase"
+	| "CONSTANT_CASE"
+	| "PascalCase"
+	| "snake_case"
+	| "unknown";
 export type StableHookResult = boolean | number[];
 /**
  * Supported cases for file names.
@@ -1773,6 +1784,58 @@ export type FilenameCase =
 	| "kebab-case"
 	| "PascalCase"
 	| "snake_case";
+export type Formats = Format[];
+export type Regex = string;
+export interface Selector {
+	kind: Kind;
+	modifiers: Modifiers;
+	scope: Scope;
+}
+export type Kind =
+	| "any"
+	| "catchParameter"
+	| "class"
+	| "classGetter"
+	| "classMethod"
+	| "classProperty"
+	| "classSetter"
+	| "const"
+	| "enum"
+	| "enumMember"
+	| "exportNamespace"
+	| "function"
+	| "importNamespace"
+	| "indexParameter"
+	| "interface"
+	| "let"
+	| "exportAlias"
+	| "importAlias"
+	| "memberLike"
+	| "namespace"
+	| "namespaceLike"
+	| "objectLiteralGetter"
+	| "objectLiteralMethod"
+	| "objectLiteralProperty"
+	| "objectLiteralSetter"
+	| "functionParameter"
+	| "typeAlias"
+	| "typeGetter"
+	| "typeLike"
+	| "typeMethod"
+	| "typeParameter"
+	| "typeProperty"
+	| "typeSetter"
+	| "using"
+	| "var"
+	| "variableLike";
+export type Modifiers = RestrictedModifier[];
+export type Scope = "any" | "global";
+export type RestrictedModifier =
+	| "abstract"
+	| "private"
+	| "protected"
+	| "readonly"
+	| "static";
 export interface RegisterProjectFolderParams {
 	path?: string;
 	setAsCurrentWorkspace: boolean;
diff --git a/packages/@biomejs/biome/configuration_schema.json b/packages/@biomejs/biome/configuration_schema.json
index 6e258cdb6080..14b36c8b3395 100644
--- a/packages/@biomejs/biome/configuration_schema.json
+++ b/packages/@biomejs/biome/configuration_schema.json
@@ -565,6 +565,17 @@
 			},
 			"additionalProperties": false
 		},
+		"Convention": {
+			"type": "object",
+			"properties": {
+				"formats": { "$ref": "#/definitions/Formats" },
+				"match": {
+					"anyOf": [{ "$ref": "#/definitions/Regex" }, { "type": "null" }]
+				},
+				"selector": { "$ref": "#/definitions/Selector" }
+			},
+			"additionalProperties": false
+		},
 		"Correctness": {
 			"description": "A list of rules that belong to this group",
 			"type": "object",
@@ -919,22 +930,6 @@
 			"type": "object",
 			"additionalProperties": false
 		},
-		"EnumMemberCase": {
-			"description": "Supported cases for TypeScript `enum` member names.",
-			"oneOf": [
-				{
-					"description": "PascalCase",
-					"type": "string",
-					"enum": ["PascalCase"]
-				},
-				{
-					"description": "CONSTANT_CASE",
-					"type": "string",
-					"enum": ["CONSTANT_CASE"]
-				},
-				{ "description": "camelCase", "type": "string", "enum": ["camelCase"] }
-			]
-		},
 		"FilenameCase": {
 			"description": "Supported cases for file names.",
 			"oneOf": [
@@ -1016,6 +1011,33 @@
 			},
 			"additionalProperties": false
 		},
+		"Format": {
+			"description": "Supported cases.",
+			"oneOf": [
+				{ "description": "camelCase", "type": "string", "enum": ["camelCase"] },
+				{
+					"description": "CONSTANT_CASE",
+					"type": "string",
+					"enum": ["CONSTANT_CASE"]
+				},
+				{
+					"description": "PascalCase",
+					"type": "string",
+					"enum": ["PascalCase"]
+				},
+				{
+					"description": "snake_case",
+					"type": "string",
+					"enum": ["snake_case"]
+				},
+				{ "description": "any case", "type": "string", "enum": ["unknown"] }
+			]
+		},
+		"Formats": {
+			"type": "array",
+			"items": { "$ref": "#/definitions/Format" },
+			"uniqueItems": true
+		},
 		"FormatterConfiguration": {
 			"description": "Generic options applied to all files",
 			"type": "object",
@@ -1341,6 +1363,47 @@
 				}
 			]
 		},
+		"Kind": {
+			"type": "string",
+			"enum": [
+				"any",
+				"catchParameter",
+				"class",
+				"classGetter",
+				"classMethod",
+				"classProperty",
+				"classSetter",
+				"const",
+				"enum",
+				"enumMember",
+				"exportNamespace",
+				"function",
+				"importNamespace",
+				"indexParameter",
+				"interface",
+				"let",
+				"exportAlias",
+				"importAlias",
+				"memberLike",
+				"namespace",
+				"namespaceLike",
+				"objectLiteralGetter",
+				"objectLiteralMethod",
+				"objectLiteralProperty",
+				"objectLiteralSetter",
+				"functionParameter",
+				"typeAlias",
+				"typeGetter",
+				"typeLike",
+				"typeMethod",
+				"typeParameter",
+				"typeProperty",
+				"typeSetter",
+				"using",
+				"var",
+				"variableLike"
+			]
+		},
 		"LineEnding": {
 			"oneOf": [
 				{
@@ -1388,6 +1451,11 @@
 			},
 			"additionalProperties": false
 		},
+		"Modifiers": {
+			"type": "array",
+			"items": { "$ref": "#/definitions/RestrictedModifier" },
+			"uniqueItems": true
+		},
 		"NamingConventionConfiguration": {
 			"anyOf": [
 				{ "$ref": "#/definitions/RulePlainConfiguration" },
@@ -1398,9 +1466,13 @@
 			"description": "Rule's options.",
 			"type": "object",
 			"properties": {
+				"custom": {
+					"type": "array",
+					"items": { "$ref": "#/definitions/Convention" }
+				},
 				"enumMemberCase": {
 					"description": "Allowed cases for _TypeScript_ `enum` member names.",
-					"allOf": [{ "$ref": "#/definitions/EnumMemberCase" }]
+					"allOf": [{ "$ref": "#/definitions/Format" }]
 				},
 				"requireAscii": {
 					"description": "If `false`, then non-ASCII characters are allowed.",
@@ -1848,6 +1920,7 @@
 		},
 		"QuoteProperties": { "type": "string", "enum": ["asNeeded", "preserve"] },
 		"QuoteStyle": { "type": "string", "enum": ["double", "single"] },
+		"Regex": { "type": "string" },
 		"RestrictedGlobalsConfiguration": {
 			"anyOf": [
 				{ "$ref": "#/definitions/RulePlainConfiguration" },
@@ -1886,6 +1959,10 @@
 			},
 			"additionalProperties": false
 		},
+		"RestrictedModifier": {
+			"type": "string",
+			"enum": ["abstract", "private", "protected", "readonly", "static"]
+		},
 		"RuleConfiguration": {
 			"anyOf": [
 				{ "$ref": "#/definitions/RulePlainConfiguration" },
@@ -2041,6 +2118,7 @@
 			},
 			"additionalProperties": false
 		},
+		"Scope": { "type": "string", "enum": ["any", "global"] },
 		"Security": {
 			"description": "A list of rules that belong to this group",
 			"type": "object",
@@ -2077,6 +2155,15 @@
 			},
 			"additionalProperties": false
 		},
+		"Selector": {
+			"type": "object",
+			"properties": {
+				"kind": { "$ref": "#/definitions/Kind" },
+				"modifiers": { "$ref": "#/definitions/Modifiers" },
+				"scope": { "$ref": "#/definitions/Scope" }
+			},
+			"additionalProperties": false
+		},
 		"Semicolons": { "type": "string", "enum": ["always", "asNeeded"] },
 		"StableHookResult": {
 			"oneOf": [