From 3d88d10f8b856e35a473313fa767f46065c87b3c Mon Sep 17 00:00:00 2001 From: SHIMA RYUHEI <65934663+islandryu@users.noreply.github.com> Date: Sat, 19 Nov 2022 21:03:07 +0900 Subject: [PATCH 1/5] fix(eslint-plugin): [prefer-readonly] report if a member's property is reassigned --- .../src/rules/prefer-readonly.ts | 5 +- .../tests/rules/prefer-readonly.test.ts | 71 +++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/prefer-readonly.ts b/packages/eslint-plugin/src/rules/prefer-readonly.ts index 3a1cd3f42f6..3a9e6cdca66 100644 --- a/packages/eslint-plugin/src/rules/prefer-readonly.ts +++ b/packages/eslint-plugin/src/rules/prefer-readonly.ts @@ -119,7 +119,10 @@ export default util.createRule({ ts.isArrayLiteralExpression(parent.parent)) ) { current = parent; - } else if (ts.isBinaryExpression(parent)) { + } else if ( + ts.isBinaryExpression(parent) && + !ts.isPropertyAccessExpression(current) + ) { return ( parent.left === current && parent.operatorToken.kind === ts.SyntaxKind.EqualsToken diff --git a/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts b/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts index 333ffc9b5ff..9d3d2db8c9e 100644 --- a/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts @@ -742,5 +742,76 @@ function ClassWithName {}>(Base: TBase) { }, ], }, + { + code: ` + class Test { + private testObj = { + prop: '', + }; + + public test(): void { + this.testObj.prop = ''; + } + } + `, + output: ` + class Test { + private readonly testObj = { + prop: '', + }; + + public test(): void { + this.testObj.prop = ''; + } + } + `, + errors: [ + { + data: { + name: 'testObj', + }, + line: 3, + messageId: 'preferReadonly', + }, + ], + }, + { + code: ` + class TestObject { + public value: number; + } + + class Test { + private testObj = new TestObject(); + + public test(): void { + this.testObj.value = 10; + } + } + `, + output: ` + class TestObject { + public value: number; + } + + class Test { + private readonly testObj = new TestObject(); + + public test(): void { + this.testObj.value = 10; + } + } + `, + errors: [ + { + data: { + name: 'testObj', + }, + line: 7, + messageId: 'preferReadonly', + }, + ], + }, ], }); + From 94c6b984ee9336adf952a6c91cdd2a3397f6de38 Mon Sep 17 00:00:00 2001 From: SHIMA RYUHEI <65934663+islandryu@users.noreply.github.com> Date: Sat, 19 Nov 2022 21:15:55 +0900 Subject: [PATCH 2/5] format --- packages/eslint-plugin/tests/rules/prefer-readonly.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts b/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts index 9d3d2db8c9e..d28c968c926 100644 --- a/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts @@ -814,4 +814,3 @@ function ClassWithName {}>(Base: TBase) { }, ], }); - From 8a147ec363c86a4273155a5d4e1a306c18934312 Mon Sep 17 00:00:00 2001 From: SHIMA RYUHEI <65934663+islandryu@users.noreply.github.com> Date: Mon, 21 Nov 2022 20:49:30 +0900 Subject: [PATCH 3/5] Add test case --- .../tests/rules/prefer-readonly.test.ts | 76 ++++++++++++++++++- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts b/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts index d28c968c926..0cf687c8f71 100644 --- a/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts @@ -339,6 +339,34 @@ class Foo { } `, }, + { + code: ` + class Test { + private testObj = { + prop: '', + }; + + public test(): void { + this.testObj = ''; + } + } + `, + }, + { + code: ` + class TestObject { + public prop: number; + } + + class Test { + private testObj = new TestObject(); + + public test(): void { + this.testObj = new TestObject(); + } + } + `, + }, ], invalid: [ { @@ -751,6 +779,16 @@ function ClassWithName {}>(Base: TBase) { public test(): void { this.testObj.prop = ''; + this.testObj.prop; + this.testObj?.prop; + this.testObj!.prop; + this.testObj!.prop = ''; + this.testObj.prop.prop = ''; + this.testObj.prop.doesSomething(); + this.testObj?.prop.prop; + this.testObj?.prop?.prop; + this.testObj.prop?.prop; + this.testObj!.prop?.prop; } } `, @@ -762,6 +800,16 @@ function ClassWithName {}>(Base: TBase) { public test(): void { this.testObj.prop = ''; + this.testObj.prop; + this.testObj?.prop; + this.testObj!.prop; + this.testObj!.prop = ''; + this.testObj.prop.prop = ''; + this.testObj.prop.doesSomething(); + this.testObj?.prop.prop; + this.testObj?.prop?.prop; + this.testObj.prop?.prop; + this.testObj!.prop?.prop; } } `, @@ -778,27 +826,47 @@ function ClassWithName {}>(Base: TBase) { { code: ` class TestObject { - public value: number; + public prop: number; } class Test { private testObj = new TestObject(); public test(): void { - this.testObj.value = 10; + this.testObj.prop = 10; + this.testObj.prop; + this.testObj?.prop; + this.testObj!.prop; + this.testObj!.prop = ''; + this.testObj.prop.prop = ''; + this.testObj.prop.doesSomething(); + this.testObj?.prop.prop; + this.testObj?.prop?.prop; + this.testObj.prop?.prop; + this.testObj!.prop?.prop; } } `, output: ` class TestObject { - public value: number; + public prop: number; } class Test { private readonly testObj = new TestObject(); public test(): void { - this.testObj.value = 10; + this.testObj.prop = 10; + this.testObj.prop; + this.testObj?.prop; + this.testObj!.prop; + this.testObj!.prop = ''; + this.testObj.prop.prop = ''; + this.testObj.prop.doesSomething(); + this.testObj?.prop.prop; + this.testObj?.prop?.prop; + this.testObj.prop?.prop; + this.testObj!.prop?.prop; } } `, From 913d934452700b37866bb97d2f9fff5fe035d9a1 Mon Sep 17 00:00:00 2001 From: SHIMA RYUHEI <65934663+islandryu@users.noreply.github.com> Date: Sat, 26 Nov 2022 19:02:38 +0900 Subject: [PATCH 4/5] fix test case --- .../tests/rules/prefer-readonly.test.ts | 267 ++++++++++++++++-- 1 file changed, 247 insertions(+), 20 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts b/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts index 0cf687c8f71..039b1faa351 100644 --- a/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts @@ -779,16 +779,6 @@ function ClassWithName {}>(Base: TBase) { public test(): void { this.testObj.prop = ''; - this.testObj.prop; - this.testObj?.prop; - this.testObj!.prop; - this.testObj!.prop = ''; - this.testObj.prop.prop = ''; - this.testObj.prop.doesSomething(); - this.testObj?.prop.prop; - this.testObj?.prop?.prop; - this.testObj.prop?.prop; - this.testObj!.prop?.prop; } } `, @@ -800,16 +790,6 @@ function ClassWithName {}>(Base: TBase) { public test(): void { this.testObj.prop = ''; - this.testObj.prop; - this.testObj?.prop; - this.testObj!.prop; - this.testObj!.prop = ''; - this.testObj.prop.prop = ''; - this.testObj.prop.doesSomething(); - this.testObj?.prop.prop; - this.testObj?.prop?.prop; - this.testObj.prop?.prop; - this.testObj!.prop?.prop; } } `, @@ -880,5 +860,252 @@ function ClassWithName {}>(Base: TBase) { }, ], }, + { + code: ` + class Test { + private testObj = { + prop: '', + }; + public test(): void { + this.testObj.prop; + } + } + `, + output: ` + class Test { + private readonly testObj = { + prop: '', + }; + public test(): void { + this.testObj.prop; + } + } + `, + errors: [ + { + data: { + name: 'testObj', + }, + line: 3, + messageId: 'preferReadonly', + }, + ], + }, + { + code: ` + class Test { + private testObj = {}; + public test(): void { + this.testObj?.prop; + } + } + `, + output: ` + class Test { + private readonly testObj = {}; + public test(): void { + this.testObj?.prop; + } + } + `, + errors: [ + { + data: { + name: 'testObj', + }, + line: 3, + messageId: 'preferReadonly', + }, + ], + }, + { + code: ` + class Test { + private testObj = {}; + public test(): void { + this.testObj!.prop; + } + } + `, + output: ` + class Test { + private readonly testObj = {}; + public test(): void { + this.testObj!.prop; + } + } + `, + errors: [ + { + data: { + name: 'testObj', + }, + line: 3, + messageId: 'preferReadonly', + }, + ], + }, + { + code: ` + class Test { + private testObj = {}; + public test(): void { + this.testObj.prop.prop = ''; + } + } + `, + output: ` + class Test { + private readonly testObj = {}; + public test(): void { + this.testObj.prop.prop = ''; + } + } + `, + errors: [ + { + data: { + name: 'testObj', + }, + line: 3, + messageId: 'preferReadonly', + }, + ], + }, + { + code: ` + class Test { + private testObj = {}; + public test(): void { + this.testObj.prop.doesSomething(); + } + } + `, + output: ` + class Test { + private readonly testObj = {}; + public test(): void { + this.testObj.prop.doesSomething(); + } + } + `, + errors: [ + { + data: { + name: 'testObj', + }, + line: 3, + messageId: 'preferReadonly', + }, + ], + }, + { + code: ` + class Test { + private testObj = {}; + public test(): void { + this.testObj?.prop.prop; + } + } + `, + output: ` + class Test { + private readonly testObj = {}; + public test(): void { + this.testObj?.prop.prop; + } + } + `, + errors: [ + { + data: { + name: 'testObj', + }, + line: 3, + messageId: 'preferReadonly', + }, + ], + }, + { + code: ` + class Test { + private testObj = {}; + public test(): void { + this.testObj?.prop?.prop; + } + } + `, + output: ` + class Test { + private readonly testObj = {}; + public test(): void { + this.testObj?.prop?.prop; + } + } + `, + errors: [ + { + data: { + name: 'testObj', + }, + line: 3, + messageId: 'preferReadonly', + }, + ], + }, + { + code: ` + class Test { + private testObj = {}; + public test(): void { + this.testObj.prop?.prop; + } + } + `, + output: ` + class Test { + private readonly testObj = {}; + public test(): void { + this.testObj.prop?.prop; + } + } + `, + errors: [ + { + data: { + name: 'testObj', + }, + line: 3, + messageId: 'preferReadonly', + }, + ], + }, + { + code: ` + class Test { + private testObj = {}; + public test(): void { + this.testObj!.prop?.prop; + } + } + `, + output: ` + class Test { + private readonly testObj = {}; + public test(): void { + this.testObj!.prop?.prop; + } + } + `, + errors: [ + { + data: { + name: 'testObj', + }, + line: 3, + messageId: 'preferReadonly', + }, + ], + }, ], }); From 9c1de04ba2adb3784406b17cde98b9e1a7f8d56d Mon Sep 17 00:00:00 2001 From: SHIMA RYUHEI <65934663+islandryu@users.noreply.github.com> Date: Sat, 26 Nov 2022 19:06:33 +0900 Subject: [PATCH 5/5] fix test case --- .../tests/rules/prefer-readonly.test.ts | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts b/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts index 039b1faa351..10f2e3d1e07 100644 --- a/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts @@ -814,16 +814,6 @@ function ClassWithName {}>(Base: TBase) { public test(): void { this.testObj.prop = 10; - this.testObj.prop; - this.testObj?.prop; - this.testObj!.prop; - this.testObj!.prop = ''; - this.testObj.prop.prop = ''; - this.testObj.prop.doesSomething(); - this.testObj?.prop.prop; - this.testObj?.prop?.prop; - this.testObj.prop?.prop; - this.testObj!.prop?.prop; } } `, @@ -837,16 +827,6 @@ function ClassWithName {}>(Base: TBase) { public test(): void { this.testObj.prop = 10; - this.testObj.prop; - this.testObj?.prop; - this.testObj!.prop; - this.testObj!.prop = ''; - this.testObj.prop.prop = ''; - this.testObj.prop.doesSomething(); - this.testObj?.prop.prop; - this.testObj?.prop?.prop; - this.testObj.prop?.prop; - this.testObj!.prop?.prop; } } `,