diff --git a/.changeset/red-baboons-rush.md b/.changeset/red-baboons-rush.md new file mode 100644 index 000000000000..358b5ebedc49 --- /dev/null +++ b/.changeset/red-baboons-rush.md @@ -0,0 +1,7 @@ +--- +"@biomejs/biome": patch +--- + +Fixed [#6695](https://github.com/biomejs/biome/issues/6695): [`useNamingConvention`](https://biomejs.dev/linter/rules/use-naming-convention/) now correctly reports TypeScript parameter properties with modifiers. + +Previously, constructor parameter properties with modifiers like `private` or `readonly` were not checked against naming conventions. These properties are now treated consistently with regular class properties. 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 77ed218bac19..bec408780910 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 @@ -1206,7 +1206,18 @@ fn selector_from_binding_declaration(decl: &AnyJsBindingDeclaration) -> Option Some(Kind::FunctionParameter.into()), AnyJsBindingDeclaration::JsCatchDeclaration(_) => Some(Kind::CatchParameter.into()), - AnyJsBindingDeclaration::TsPropertyParameter(_) => Some(Kind::ClassProperty.into()), + AnyJsBindingDeclaration::TsPropertyParameter(param) => { + let modifiers: BitFlags = (¶m.modifiers()).into(); + if modifiers.contains(Modifier::Override) { + // Ignore explicitly overridden members + None + } else { + Some(Selector::with_modifiers( + Kind::ClassProperty, + to_restricted_modifiers(modifiers), + )) + } + }, AnyJsBindingDeclaration::TsIndexSignatureParameter(member_name) => { if let Some(member) = member_name.parent::<>() { selector_from_class_member(&member) diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterPropertyWithModifiers.options.json b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterPropertyWithModifiers.options.json new file mode 100644 index 000000000000..9114e9ddf63b --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterPropertyWithModifiers.options.json @@ -0,0 +1,41 @@ +{ + "$schema": "../../../../../../packages/@biomejs/biome/configuration_schema.json", + "linter": { + "rules": { + "style": { + "useNamingConvention": { + "level": "error", + "options": { + "strictCase": false, + "requireAscii": true, + "conventions": [ + { + "selector": { + "kind": "classProperty", + "modifiers": ["private", "readonly"] + }, + "formats": ["CONSTANT_CASE", "camelCase"], + "match": "_(.+)" + }, + { + "selector": { + "kind": "classProperty", + "modifiers": ["private"] + }, + "formats": ["camelCase"], + "match": "_(.+)" + }, + { + "selector": { + "kind": "classMember", + "modifiers": ["private"] + }, + "match": "_(.+)" + } + ] + } + } + } + } + } +} \ No newline at end of file diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterPropertyWithModifiers.ts b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterPropertyWithModifiers.ts new file mode 100644 index 000000000000..d6622fafe764 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterPropertyWithModifiers.ts @@ -0,0 +1,7 @@ +class SomeClass { + private readonly _private: string; + private readonly _private2: string; + + // invalid, should have an underscore according to rules + constructor(private readonly private3: string) {} +} \ No newline at end of file diff --git a/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterPropertyWithModifiers.ts.snap b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterPropertyWithModifiers.ts.snap new file mode 100644 index 000000000000..bc8d55bce22e --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/style/useNamingConvention/invalidParameterPropertyWithModifiers.ts.snap @@ -0,0 +1,28 @@ +--- +source: crates/biome_js_analyze/tests/spec_tests.rs +expression: invalidParameterPropertyWithModifiers.ts +--- +# Input +```ts +class SomeClass { + private readonly _private: string; + private readonly _private2: string; + + // invalid, should have an underscore according to rules + constructor(private readonly private3: string) {} +} +``` + +# Diagnostics +``` +invalidParameterPropertyWithModifiers.ts:6:31 lint/style/useNamingConvention ━━━━━━━━━━━━━━━━━━━━━━━ + + i This private readonly class property name should match the following regex /_(.+)/. + + 5 │ // invalid, should have an underscore according to rules + > 6 │ constructor(private readonly private3: string) {} + │ ^^^^^^^^ + 7 │ } + + +``` diff --git a/crates/biome_js_syntax/src/modifier_ext.rs b/crates/biome_js_syntax/src/modifier_ext.rs index cb689fc12310..baa15632dc4b 100644 --- a/crates/biome_js_syntax/src/modifier_ext.rs +++ b/crates/biome_js_syntax/src/modifier_ext.rs @@ -199,6 +199,14 @@ impl From<&TsMethodSignatureModifierList> for enumflags2::BitFlags { .fold(Self::empty(), |acc, m| acc | m) } } +impl From<&crate::TsPropertyParameterModifierList> for enumflags2::BitFlags { + fn from(value: &crate::TsPropertyParameterModifierList) -> Self { + value + .into_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)]