diff --git a/.changeset/fuzzy-dragons-invent.md b/.changeset/fuzzy-dragons-invent.md new file mode 100644 index 000000000000..ed45d1807338 --- /dev/null +++ b/.changeset/fuzzy-dragons-invent.md @@ -0,0 +1,5 @@ +--- +"@biomejs/biome": patch +--- + +Fixed [#7948](https://github.com/biomejs/biome/issues/7948): The `useReadonlyClassProperties` code fix when `checkAllProperties` is enabled will no longer insert a newline after `readonly` and the class property. diff --git a/crates/biome_js_analyze/src/lint/style/use_readonly_class_properties.rs b/crates/biome_js_analyze/src/lint/style/use_readonly_class_properties.rs index 5c690f39c7db..ac4b770d14b8 100644 --- a/crates/biome_js_analyze/src/lint/style/use_readonly_class_properties.rs +++ b/crates/biome_js_analyze/src/lint/style/use_readonly_class_properties.rs @@ -219,7 +219,7 @@ impl Rule for UseReadonlyClassProperties { ); if let Some(modified_member) = - extract_property_member_name_trimmed_whitespace(member_name.clone()) + extract_class_member_name_trimmed_whitespace(member_name.clone()) { let mut builder = make::js_property_class_member(replace_modifiers, modified_member); @@ -353,10 +353,10 @@ fn collect_non_readonly_constructor_parameters( .collect() } -/// Removes leading whitespace from `#privateProperty` names. Without this, the name might include -/// unwanted whitespace (e.g., "\n #privateProperty"). This ensures that when adding modifiers like -/// `readonly`, they are appended correctly without being affected by the whitespace. -fn extract_property_member_name_trimmed_whitespace( +/// Removes leading trivia from class member names. Without this, the name might include +/// unwanted trivia (e.g., "\n #privateProperty"). This ensures that when adding modifiers like +/// `readonly`, they are appended correctly without being affected by the trivia. +fn extract_class_member_name_trimmed_whitespace( member_name: AnyJsClassMemberName, ) -> Option { match member_name { @@ -367,6 +367,13 @@ fn extract_property_member_name_trimmed_whitespace( Some(AnyJsClassMemberName::JsPrivateClassMemberName(trimmed)) } + AnyJsClassMemberName::JsLiteralMemberName(name) => { + let value = name.value().ok()?; + let new_value = value.with_leading_trivia([]); + let trimmed = name.replace_token_discard_trivia(value, new_value)?; + + Some(AnyJsClassMemberName::JsLiteralMemberName(trimmed)) + } _ => Some(member_name), } } diff --git a/crates/biome_js_analyze/tests/specs/style/useReadonlyClassProperties/invalid_checkAllPropertiesTrue.ts b/crates/biome_js_analyze/tests/specs/style/useReadonlyClassProperties/invalid_checkAllPropertiesTrue.ts index 0e02dce1185c..7d44dce2a2ee 100644 --- a/crates/biome_js_analyze/tests/specs/style/useReadonlyClassProperties/invalid_checkAllPropertiesTrue.ts +++ b/crates/biome_js_analyze/tests/specs/style/useReadonlyClassProperties/invalid_checkAllPropertiesTrue.ts @@ -3,6 +3,7 @@ class Example1 { private prop1: number = 42; protected prop2: string; public prop3: string; + prop4: string; } class Example2 { diff --git a/crates/biome_js_analyze/tests/specs/style/useReadonlyClassProperties/invalid_checkAllPropertiesTrue.ts.snap b/crates/biome_js_analyze/tests/specs/style/useReadonlyClassProperties/invalid_checkAllPropertiesTrue.ts.snap index ac5fad53bdc8..006e06301e78 100644 --- a/crates/biome_js_analyze/tests/specs/style/useReadonlyClassProperties/invalid_checkAllPropertiesTrue.ts.snap +++ b/crates/biome_js_analyze/tests/specs/style/useReadonlyClassProperties/invalid_checkAllPropertiesTrue.ts.snap @@ -1,5 +1,6 @@ --- source: crates/biome_js_analyze/tests/spec_tests.rs +assertion_line: 151 expression: invalid_checkAllPropertiesTrue.ts --- # Input @@ -9,6 +10,7 @@ class Example1 { private prop1: number = 42; protected prop2: string; public prop3: string; + prop4: string; } class Example2 { @@ -119,7 +121,7 @@ invalid_checkAllPropertiesTrue.ts:4:12 lint/style/useReadonlyClassProperties FI > 4 │ protected prop2: string; │ ^^^^^ 5 │ public prop3: string; - 6 │ } + 6 │ prop4: string; i Using readonly improves code safety, clarity, and helps prevent unintended mutations. @@ -139,8 +141,8 @@ invalid_checkAllPropertiesTrue.ts:5:9 lint/style/useReadonlyClassProperties FIX 4 │ protected prop2: string; > 5 │ public prop3: string; │ ^^^^^ - 6 │ } - 7 │ + 6 │ prop4: string; + 7 │ } i Using readonly improves code safety, clarity, and helps prevent unintended mutations. @@ -152,294 +154,315 @@ invalid_checkAllPropertiesTrue.ts:5:9 lint/style/useReadonlyClassProperties FIX ``` ``` -invalid_checkAllPropertiesTrue.ts:10:11 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:6:2 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━━━ + + i Member 'prop4' is never reassigned. + + 4 │ protected prop2: string; + 5 │ public prop3: string; + > 6 │ prop4: string; + │ ^^^^^ + 7 │ } + 8 │ + + i Using readonly improves code safety, clarity, and helps prevent unintended mutations. + + i Unsafe fix: Add readonly decorator. + + 6 │ → readonly·prop4:·string; + │ +++++++++ + +``` + +``` +invalid_checkAllPropertiesTrue.ts:11:11 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ i Member 'prop1' is never reassigned. - 8 │ class Example2 { - 9 │ constructor( - > 10 │ private prop1: number, + 9 │ class Example2 { + 10 │ constructor( + > 11 │ private prop1: number, │ ^^^^^ - 11 │ public prop2: string, - 12 │ protected prop3: string, + 12 │ public prop2: string, + 13 │ protected prop3: string, i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 10 │ → → private·readonly·prop1:·number, + 11 │ → → private·readonly·prop1:·number, │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:11:10 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:12:10 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ i Member 'prop2' is never reassigned. - 9 │ constructor( - 10 │ private prop1: number, - > 11 │ public prop2: string, + 10 │ constructor( + 11 │ private prop1: number, + > 12 │ public prop2: string, │ ^^^^^ - 12 │ protected prop3: string, - 13 │ ) { + 13 │ protected prop3: string, + 14 │ ) { i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 11 │ → → public·readonly·prop2:·string, + 12 │ → → public·readonly·prop2:·string, │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:12:13 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:13:13 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ i Member 'prop3' is never reassigned. - 10 │ private prop1: number, - 11 │ public prop2: string, - > 12 │ protected prop3: string, + 11 │ private prop1: number, + 12 │ public prop2: string, + > 13 │ protected prop3: string, │ ^^^^^ - 13 │ ) { - 14 │ } + 14 │ ) { + 15 │ } i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 12 │ → → protected·readonly·prop3:·string, + 13 │ → → protected·readonly·prop3:·string, │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:18:2 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:19:2 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━━ i Member '#prop0' is never reassigned. - 17 │ class Example3 { - > 18 │ #prop0: number = 42; + 18 │ class Example3 { + > 19 │ #prop0: number = 42; │ ^^^^^^ - 19 │ private prop1: number = 42; - 20 │ protected prop2: number; + 20 │ private prop1: number = 42; + 21 │ protected prop2: number; i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 18 │ → readonly·#prop0:·number·=·42; + 19 │ → readonly·#prop0:·number·=·42; │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:19:10 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:20:10 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ i Member 'prop1' is never reassigned. - 17 │ class Example3 { - 18 │ #prop0: number = 42; - > 19 │ private prop1: number = 42; + 18 │ class Example3 { + 19 │ #prop0: number = 42; + > 20 │ private prop1: number = 42; │ ^^^^^ - 20 │ protected prop2: number; - 21 │ public prop3: number; + 21 │ protected prop2: number; + 22 │ public prop3: number; i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 19 │ → private·readonly·prop1:·number·=·42; + 20 │ → private·readonly·prop1:·number·=·42; │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:20:12 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:21:12 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ i Member 'prop2' is never reassigned. - 18 │ #prop0: number = 42; - 19 │ private prop1: number = 42; - > 20 │ protected prop2: number; + 19 │ #prop0: number = 42; + 20 │ private prop1: number = 42; + > 21 │ protected prop2: number; │ ^^^^^ - 21 │ public prop3: number; - 22 │ + 22 │ public prop3: number; + 23 │ i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 20 │ → protected·readonly·prop2:·number; + 21 │ → protected·readonly·prop2:·number; │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:21:9 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:22:9 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━━ i Member 'prop3' is never reassigned. - 19 │ private prop1: number = 42; - 20 │ protected prop2: number; - > 21 │ public prop3: number; + 20 │ private prop1: number = 42; + 21 │ protected prop2: number; + > 22 │ public prop3: number; │ ^^^^^ - 22 │ - 23 │ constructor(prop0: number, prop1: number, prop2: number, prop3: number, private prop4: number, public prop5: number, protected prop6: number) { + 23 │ + 24 │ constructor(prop0: number, prop1: number, prop2: number, prop3: number, private prop4: number, public prop5: number, protected prop6: number) { i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 21 │ → public·readonly·prop3:·number; + 22 │ → public·readonly·prop3:·number; │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:23:82 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:24:82 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ i Member 'prop4' is never reassigned. - 21 │ public prop3: number; - 22 │ - > 23 │ constructor(prop0: number, prop1: number, prop2: number, prop3: number, private prop4: number, public prop5: number, protected prop6: number) { + 22 │ public prop3: number; + 23 │ + > 24 │ constructor(prop0: number, prop1: number, prop2: number, prop3: number, private prop4: number, public prop5: number, protected prop6: number) { │ ^^^^^ - 24 │ this.#prop0 = prop0; - 25 │ this.prop1 = prop1; + 25 │ this.#prop0 = prop0; + 26 │ this.prop1 = prop1; i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 23 │ → constructor(prop0:·number,·prop1:·number,·prop2:·number,·prop3:·number,·private·readonly·prop4:·number,·public·prop5:·number,·protected·prop6:·number)·{ + 24 │ → constructor(prop0:·number,·prop1:·number,·prop2:·number,·prop3:·number,·private·readonly·prop4:·number,·public·prop5:·number,·protected·prop6:·number)·{ │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:23:104 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:24:104 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━ i Member 'prop5' is never reassigned. - 21 │ public prop3: number; - 22 │ - > 23 │ constructor(prop0: number, prop1: number, prop2: number, prop3: number, private prop4: number, public prop5: number, protected prop6: number) { + 22 │ public prop3: number; + 23 │ + > 24 │ constructor(prop0: number, prop1: number, prop2: number, prop3: number, private prop4: number, public prop5: number, protected prop6: number) { │ ^^^^^ - 24 │ this.#prop0 = prop0; - 25 │ this.prop1 = prop1; + 25 │ this.#prop0 = prop0; + 26 │ this.prop1 = prop1; i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 23 │ → constructor(prop0:·number,·prop1:·number,·prop2:·number,·prop3:·number,·private·prop4:·number,·public·readonly·prop5:·number,·protected·prop6:·number)·{ + 24 │ → constructor(prop0:·number,·prop1:·number,·prop2:·number,·prop3:·number,·private·prop4:·number,·public·readonly·prop5:·number,·protected·prop6:·number)·{ │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:23:129 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:24:129 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━ i Member 'prop6' is never reassigned. - 21 │ public prop3: number; - 22 │ - > 23 │ constructor(prop0: number, prop1: number, prop2: number, prop3: number, private prop4: number, public prop5: number, protected prop6: number) { + 22 │ public prop3: number; + 23 │ + > 24 │ constructor(prop0: number, prop1: number, prop2: number, prop3: number, private prop4: number, public prop5: number, protected prop6: number) { │ ^^^^^ - 24 │ this.#prop0 = prop0; - 25 │ this.prop1 = prop1; + 25 │ this.#prop0 = prop0; + 26 │ this.prop1 = prop1; i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 23 │ → constructor(prop0:·number,·prop1:·number,·prop2:·number,·prop3:·number,·private·prop4:·number,·public·prop5:·number,·protected·readonly·prop6:·number)·{ + 24 │ → constructor(prop0:·number,·prop1:·number,·prop2:·number,·prop3:·number,·private·prop4:·number,·public·prop5:·number,·protected·readonly·prop6:·number)·{ │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:33:2 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:34:2 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━━ i Member '#prop0' is never reassigned. - 31 │ // with some getters/ reads do not affect readonly - 32 │ class Example4 { - > 33 │ #prop0: number = 42; + 32 │ // with some getters/ reads do not affect readonly + 33 │ class Example4 { + > 34 │ #prop0: number = 42; │ ^^^^^^ - 34 │ private prop1: number = 42; - 35 │ protected prop2: number; + 35 │ private prop1: number = 42; + 36 │ protected prop2: number; i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 33 │ → readonly·#prop0:·number·=·42; + 34 │ → readonly·#prop0:·number·=·42; │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:34:10 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:35:10 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ i Member 'prop1' is never reassigned. - 32 │ class Example4 { - 33 │ #prop0: number = 42; - > 34 │ private prop1: number = 42; + 33 │ class Example4 { + 34 │ #prop0: number = 42; + > 35 │ private prop1: number = 42; │ ^^^^^ - 35 │ protected prop2: number; - 36 │ public prop3: number; + 36 │ protected prop2: number; + 37 │ public prop3: number; i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 34 │ → private·readonly·prop1:·number·=·42; + 35 │ → private·readonly·prop1:·number·=·42; │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:35:12 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:36:12 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━ i Member 'prop2' is never reassigned. - 33 │ #prop0: number = 42; - 34 │ private prop1: number = 42; - > 35 │ protected prop2: number; + 34 │ #prop0: number = 42; + 35 │ private prop1: number = 42; + > 36 │ protected prop2: number; │ ^^^^^ - 36 │ public prop3: number; - 37 │ + 37 │ public prop3: number; + 38 │ i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 35 │ → protected·readonly·prop2:·number; + 36 │ → protected·readonly·prop2:·number; │ +++++++++ ``` ``` -invalid_checkAllPropertiesTrue.ts:36:9 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━━ +invalid_checkAllPropertiesTrue.ts:37:9 lint/style/useReadonlyClassProperties FIXABLE ━━━━━━━━━━━━━ i Member 'prop3' is never reassigned. - 34 │ private prop1: number = 42; - 35 │ protected prop2: number; - > 36 │ public prop3: number; + 35 │ private prop1: number = 42; + 36 │ protected prop2: number; + > 37 │ public prop3: number; │ ^^^^^ - 37 │ - 38 │ constructor(prop0: number, prop1: number, prop2: number, prop3: number) { + 38 │ + 39 │ constructor(prop0: number, prop1: number, prop2: number, prop3: number) { i Using readonly improves code safety, clarity, and helps prevent unintended mutations. i Unsafe fix: Add readonly decorator. - 36 │ → public·readonly·prop3:·number; + 37 │ → public·readonly·prop3:·number; │ +++++++++ ```