diff --git a/.changeset/no_unused_private_class_members_bug.md b/.changeset/no_unused_private_class_members_bug.md new file mode 100644 index 000000000000..8f61951d941b --- /dev/null +++ b/.changeset/no_unused_private_class_members_bug.md @@ -0,0 +1,18 @@ +--- +"@biomejs/biome": patch +--- + +Fixed [#7192](https://github.com/biomejs/biome/issues/7192): +`noUnusedPrivateClassMembers` now treats private members in compound assignments (+=, -=, ??=, etc.) as used, +while plain assignments (=) do not count as usage. + +Example that is now correctly flagged: + +```typescript +class App { + #persistenceRequest: Promise | undefined; + saveData() { + this.#persistenceRequest += 2; + } +} +``` diff --git a/crates/biome_js_analyze/src/lint/correctness/no_unused_private_class_members.rs b/crates/biome_js_analyze/src/lint/correctness/no_unused_private_class_members.rs index 28efac642c93..8eac7defe49e 100644 --- a/crates/biome_js_analyze/src/lint/correctness/no_unused_private_class_members.rs +++ b/crates/biome_js_analyze/src/lint/correctness/no_unused_private_class_members.rs @@ -11,8 +11,8 @@ use biome_diagnostics::Severity; use biome_js_semantic::ReferencesExtensions; use biome_js_syntax::{ AnyJsClassMember, AnyJsClassMemberName, AnyJsComputedMember, AnyJsExpression, - AnyJsFormalParameter, AnyJsName, JsAssignmentExpression, JsClassDeclaration, JsSyntaxKind, - JsSyntaxNode, TsAccessibilityModifier, TsPropertyParameter, + AnyJsFormalParameter, AnyJsName, JsAssignmentExpression, JsAssignmentOperator, + JsClassDeclaration, JsSyntaxKind, JsSyntaxNode, TsAccessibilityModifier, TsPropertyParameter, }; use biome_rowan::{ AstNode, AstNodeList, AstSeparatedList, BatchMutationExt, SyntaxNodeOptionExt, TextRange, @@ -268,7 +268,11 @@ fn traverse_members_usage( is_write_only(&js_name) == Some(true) && !private_member.is_accessor(); let is_in_update_expression = is_in_update_expression(&js_name); - if is_in_update_expression || is_write_only { + if is_in_update_expression { + return false; + } + + if is_write_only { return true; } @@ -423,10 +427,19 @@ fn is_in_update_expression(js_name: &AnyJsName) -> bool { return false; } - matches!( - grand_parent.kind(), - JsSyntaxKind::JS_POST_UPDATE_EXPRESSION | JsSyntaxKind::JS_PRE_UPDATE_EXPRESSION - ) + // grand_parent can also be js expression statement + match grand_parent.kind() { + JsSyntaxKind::JS_POST_UPDATE_EXPRESSION | JsSyntaxKind::JS_PRE_UPDATE_EXPRESSION => true, + JsSyntaxKind::JS_ASSIGNMENT_EXPRESSION => { + if let Some(assign_expr) = JsAssignmentExpression::cast(grand_parent.clone()) + && let Ok(op_kind) = assign_expr.operator() + { + return op_kind != JsAssignmentOperator::Assign; + } + false + } + _ => false, + } } impl AnyMember { diff --git a/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.js b/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.js index a50f161afb3b..4ee8de782e8d 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.js +++ b/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.js @@ -14,14 +14,6 @@ class OnlyWrite { } } -class SelfUpdate { - #usedOnlyToUpdateItself = 5; - - method() { - this.#usedOnlyToUpdateItself++; - } -} - class Accessor { get #unusedAccessor() {} set #unusedAccessor(value) {} diff --git a/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.js.snap b/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.js.snap index 0559a78fe7fd..9491bea45271 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.js.snap +++ b/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.js.snap @@ -1,5 +1,6 @@ --- source: crates/biome_js_analyze/tests/spec_tests.rs +assertion_line: 152 expression: invalid.js --- # Input @@ -20,14 +21,6 @@ class OnlyWrite { } } -class SelfUpdate { - #usedOnlyToUpdateItself = 5; - - method() { - this.#usedOnlyToUpdateItself++; - } -} - class Accessor { get #unusedAccessor() {} set #unusedAccessor(value) {} @@ -133,156 +126,90 @@ invalid.js:10:2 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━ ``` ``` -invalid.js:18:2 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:18:6 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! This private class member is defined but never used. - 17 │ class SelfUpdate { - > 18 │ #usedOnlyToUpdateItself = 5; - │ ^^^^^^^^^^^^^^^^^^^^^^^ - 19 │ - 20 │ method() { - - i Unsafe fix: Remove unused declaration. - - 16 16 │ - 17 17 │ class SelfUpdate { - 18 │ - → #usedOnlyToUpdateItself·=·5; - 19 18 │ - 20 19 │ method() { - - -``` - -``` -invalid.js:26:6 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! This private class member is defined but never used. - - 25 │ class Accessor { - > 26 │ get #unusedAccessor() {} + 17 │ class Accessor { + > 18 │ get #unusedAccessor() {} │ ^^^^^^^^^^^^^^^ - 27 │ set #unusedAccessor(value) {} - 28 │ } + 19 │ set #unusedAccessor(value) {} + 20 │ } i Unsafe fix: Remove unused declaration. - 24 24 │ - 25 25 │ class Accessor { - 26 │ - → get·#unusedAccessor()·{} - 27 26 │ set #unusedAccessor(value) {} - 28 27 │ } + 16 16 │ + 17 17 │ class Accessor { + 18 │ - → get·#unusedAccessor()·{} + 19 18 │ set #unusedAccessor(value) {} + 20 19 │ } ``` ``` -invalid.js:27:6 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:19:6 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! This private class member is defined but never used. - 25 │ class Accessor { - 26 │ get #unusedAccessor() {} - > 27 │ set #unusedAccessor(value) {} + 17 │ class Accessor { + 18 │ get #unusedAccessor() {} + > 19 │ set #unusedAccessor(value) {} │ ^^^^^^^^^^^^^^^ - 28 │ } - 29 │ + 20 │ } + 21 │ i Unsafe fix: Remove unused declaration. - 25 25 │ class Accessor { - 26 26 │ get #unusedAccessor() {} - 27 │ - → set·#unusedAccessor(value)·{} - 28 27 │ } - 29 28 │ + 17 17 │ class Accessor { + 18 18 │ get #unusedAccessor() {} + 19 │ - → set·#unusedAccessor(value)·{} + 20 19 │ } + 21 20 │ ``` ``` -invalid.js:31:2 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:23:2 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! This private class member is defined but never used. - 30 │ class First { - > 31 │ #unusedMemberInFirstClass = 5; + 22 │ class First { + > 23 │ #unusedMemberInFirstClass = 5; │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - 32 │ } - 33 │ + 24 │ } + 25 │ i Unsafe fix: Remove unused declaration. - 29 29 │ - 30 30 │ class First { - 31 │ - → #unusedMemberInFirstClass·=·5; - 32 31 │ } - 33 32 │ + 21 21 │ + 22 22 │ class First { + 23 │ - → #unusedMemberInFirstClass·=·5; + 24 23 │ } + 25 24 │ ``` ``` -invalid.js:35:2 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:27:2 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! This private class member is defined but never used. - 34 │ class Foo { - > 35 │ #usedOnlyInWrite = 5; + 26 │ class Foo { + > 27 │ #usedOnlyInWrite = 5; │ ^^^^^^^^^^^^^^^^ - 36 │ method() { - 37 │ this.#usedOnlyInWrite = 42; - - i Unsafe fix: Remove unused declaration. - - 33 33 │ - 34 34 │ class Foo { - 35 │ - → #usedOnlyInWrite·=·5; - 36 35 │ method() { - 37 36 │ this.#usedOnlyInWrite = 42; - - -``` - -``` -invalid.js:42:2 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! This private class member is defined but never used. - - 41 │ class Foo { - > 42 │ #usedOnlyInWriteStatement = 5; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^ - 43 │ method() { - 44 │ this.#usedOnlyInWriteStatement += 42; - - i Unsafe fix: Remove unused declaration. - - 40 40 │ - 41 41 │ class Foo { - 42 │ - → #usedOnlyInWriteStatement·=·5; - 43 42 │ method() { - 44 43 │ this.#usedOnlyInWriteStatement += 42; - - -``` - -``` -invalid.js:49:2 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! This private class member is defined but never used. - - 48 │ class C { - > 49 │ #usedOnlyInIncrement; - │ ^^^^^^^^^^^^^^^^^^^^ - 50 │ - 51 │ foo() { + 28 │ method() { + 29 │ this.#usedOnlyInWrite = 42; i Unsafe fix: Remove unused declaration. - 47 47 │ - 48 48 │ class C { - 49 │ - → #usedOnlyInIncrement; - 50 49 │ - 51 50 │ foo() { + 25 25 │ + 26 26 │ class Foo { + 27 │ - → #usedOnlyInWrite·=·5; + 28 27 │ method() { + 29 28 │ this.#usedOnlyInWrite = 42; ``` diff --git a/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.ts b/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.ts index 05e41dc353e2..6384c303730b 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.ts +++ b/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.ts @@ -21,14 +21,6 @@ class TsOnlyWrite { } } -class TsSelfUpdate { - private usedOnlyToUpdateItself = 5; - - method() { - this.usedOnlyToUpdateItself++; - } -} - class TsAccessor { private get unusedAccessor() { } private set unusedAccessor(value) { } diff --git a/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.ts.snap b/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.ts.snap index e7d8b3bcf595..31a53878dae0 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.ts.snap +++ b/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/invalid.ts.snap @@ -1,6 +1,6 @@ --- source: crates/biome_js_analyze/tests/spec_tests.rs -assertion_line: 146 +assertion_line: 152 expression: invalid.ts --- # Input @@ -28,14 +28,6 @@ class TsOnlyWrite { } } -class TsSelfUpdate { - private usedOnlyToUpdateItself = 5; - - method() { - this.usedOnlyToUpdateItself++; - } -} - class TsAccessor { private get unusedAccessor() { } private set unusedAccessor(value) { } @@ -149,114 +141,92 @@ invalid.ts:17:10 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━ ``` ``` -invalid.ts:25:10 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! This private class member is defined but never used. - - 24 │ class TsSelfUpdate { - > 25 │ private usedOnlyToUpdateItself = 5; - │ ^^^^^^^^^^^^^^^^^^^^^^ - 26 │ - 27 │ method() { - - i Unsafe fix: Remove unused declaration. - - 23 23 │ - 24 24 │ class TsSelfUpdate { - 25 │ - → private·usedOnlyToUpdateItself·=·5; - 26 25 │ - 27 26 │ method() { - - -``` - -``` -invalid.ts:33:14 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.ts:25:14 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! This private class member is defined but never used. - 32 │ class TsAccessor { - > 33 │ private get unusedAccessor() { } + 24 │ class TsAccessor { + > 25 │ private get unusedAccessor() { } │ ^^^^^^^^^^^^^^ - 34 │ private set unusedAccessor(value) { } - 35 │ } + 26 │ private set unusedAccessor(value) { } + 27 │ } i Unsafe fix: Remove unused declaration. - 31 31 │ - 32 32 │ class TsAccessor { - 33 │ - → private·get·unusedAccessor()·{·} - 34 33 │ private set unusedAccessor(value) { } - 35 34 │ } + 23 23 │ + 24 24 │ class TsAccessor { + 25 │ - → private·get·unusedAccessor()·{·} + 26 25 │ private set unusedAccessor(value) { } + 27 26 │ } ``` ``` -invalid.ts:34:14 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.ts:26:14 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! This private class member is defined but never used. - 32 │ class TsAccessor { - 33 │ private get unusedAccessor() { } - > 34 │ private set unusedAccessor(value) { } + 24 │ class TsAccessor { + 25 │ private get unusedAccessor() { } + > 26 │ private set unusedAccessor(value) { } │ ^^^^^^^^^^^^^^ - 35 │ } - 36 │ + 27 │ } + 28 │ i Unsafe fix: Remove unused declaration. - 32 32 │ class TsAccessor { - 33 33 │ private get unusedAccessor() { } - 34 │ - → private·set·unusedAccessor(value)·{·} - 35 34 │ } - 36 35 │ + 24 24 │ class TsAccessor { + 25 25 │ private get unusedAccessor() { } + 26 │ - → private·set·unusedAccessor(value)·{·} + 27 26 │ } + 28 27 │ ``` ``` -invalid.ts:39:10 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.ts:31:10 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! This private class member is defined but never used. - 37 │ // github.com/biomejs/biome/issues/6165 - 38 │ class TsBioo2 { - > 39 │ private unusedProperty = 5; + 29 │ // github.com/biomejs/biome/issues/6165 + 30 │ class TsBioo2 { + > 31 │ private unusedProperty = 5; │ ^^^^^^^^^^^^^^ - 40 │ private unusedMethod() {} - 41 │ + 32 │ private unusedMethod() {} + 33 │ i Unsafe fix: Remove unused declaration. - 37 37 │ // github.com/biomejs/biome/issues/6165 - 38 38 │ class TsBioo2 { - 39 │ - → private·unusedProperty·=·5; - 40 39 │ private unusedMethod() {} - 41 40 │ + 29 29 │ // github.com/biomejs/biome/issues/6165 + 30 30 │ class TsBioo2 { + 31 │ - → private·unusedProperty·=·5; + 32 31 │ private unusedMethod() {} + 33 32 │ ``` ``` -invalid.ts:40:10 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.ts:32:10 lint/correctness/noUnusedPrivateClassMembers FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! This private class member is defined but never used. - 38 │ class TsBioo2 { - 39 │ private unusedProperty = 5; - > 40 │ private unusedMethod() {} + 30 │ class TsBioo2 { + 31 │ private unusedProperty = 5; + > 32 │ private unusedMethod() {} │ ^^^^^^^^^^^^ - 41 │ - 42 │ private usedProperty = 4; + 33 │ + 34 │ private usedProperty = 4; i Unsafe fix: Remove unused declaration. - 38 38 │ class TsBioo2 { - 39 39 │ private unusedProperty = 5; - 40 │ - → private·unusedMethod()·{} - 41 40 │ - 42 41 │ private usedProperty = 4; + 30 30 │ class TsBioo2 { + 31 31 │ private unusedProperty = 5; + 32 │ - → private·unusedMethod()·{} + 33 32 │ + 34 33 │ private usedProperty = 4; ``` diff --git a/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/valid.js b/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/valid.js index 871a2b04e716..681a096033c9 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/valid.js +++ b/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/valid.js @@ -203,3 +203,164 @@ class UsedPostUpdateExpr { return this.#val++; } } + +class AppSelfAdd { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest += this.#persistenceRequest; + } +} + +class AppSelfSubtract { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest -= this.#persistenceRequest; + } +} + +class AppSelfMultiply { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest *= this.#persistenceRequest; + } +} + +class AppSelfDivide { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest /= this.#persistenceRequest; + } +} + +class AppSelfExponent { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest **= this.#persistenceRequest; + } +} + +class AppSelfAnd { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest &&= this.#persistenceRequest; + } +} + +class AppSelfOr { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest ||= this.#persistenceRequest; + } +} + +class AppSelfNullish { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest ??= this.#persistenceRequest; + } +} + +class AppAddAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest += 1; + } +} + +class AppSubtractAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest -= 1; + } +} + +class AppMultiplyAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest *= 2; + } +} + +class AppDivideAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest /= 2; + } +} + +class AppExponentAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest **= 2; + } +} + +class AppModuloAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest %= 2; + } +} + +class AppAndAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest &= 1; + } +} + +class AppOrAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest |= 1; + } +} + +class AppXorAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest ^= 1; + } +} + +class AppLeftShiftAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest <<= 1; + } +} + +class AppRightShiftAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest >>= 1; + } +} + +class AppUnsignedRightShiftAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest >>>= 1; + } +} + +class AppAndLogicalAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest &&= 1; + } +} + +class AppOrLogicalAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest ||= 1; + } +} + +class AppNullishAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest ??= 1; + } +} diff --git a/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/valid.js.snap b/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/valid.js.snap index 539e488c1dfc..1864b5c58f09 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/valid.js.snap +++ b/crates/biome_js_analyze/tests/specs/correctness/noUnusedPrivateClassMembers/valid.js.snap @@ -1,5 +1,6 @@ --- source: crates/biome_js_analyze/tests/spec_tests.rs +assertion_line: 152 expression: valid.js --- # Input @@ -210,4 +211,165 @@ class UsedPostUpdateExpr { } } +class AppSelfAdd { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest += this.#persistenceRequest; + } +} + +class AppSelfSubtract { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest -= this.#persistenceRequest; + } +} + +class AppSelfMultiply { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest *= this.#persistenceRequest; + } +} + +class AppSelfDivide { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest /= this.#persistenceRequest; + } +} + +class AppSelfExponent { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest **= this.#persistenceRequest; + } +} + +class AppSelfAnd { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest &&= this.#persistenceRequest; + } +} + +class AppSelfOr { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest ||= this.#persistenceRequest; + } +} + +class AppSelfNullish { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest ??= this.#persistenceRequest; + } +} + +class AppAddAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest += 1; + } +} + +class AppSubtractAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest -= 1; + } +} + +class AppMultiplyAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest *= 2; + } +} + +class AppDivideAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest /= 2; + } +} + +class AppExponentAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest **= 2; + } +} + +class AppModuloAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest %= 2; + } +} + +class AppAndAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest &= 1; + } +} + +class AppOrAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest |= 1; + } +} + +class AppXorAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest ^= 1; + } +} + +class AppLeftShiftAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest <<= 1; + } +} + +class AppRightShiftAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest >>= 1; + } +} + +class AppUnsignedRightShiftAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest >>>= 1; + } +} + +class AppAndLogicalAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest &&= 1; + } +} + +class AppOrLogicalAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest ||= 1; + } +} + +class AppNullishAssignment { + #persistenceRequest = 0; + saveData() { + this.#persistenceRequest ??= 1; + } +} + ```